Author Topic: (Possibly) A simple pointer question  (Read 8204 times)

0 Members and 4 Guests are viewing this topic.

Offline klr5205Topic starter

  • Regular Contributor
  • *
  • Posts: 115
  • Country: us
(Possibly) A simple pointer question
« on: June 05, 2017, 05:08:05 pm »
I'm not much of a programmer, so I was hoping someone could point me in the right direction as far as what's probably going wrong here....

If I have this function:
Code: [Select]
void WriteLCDString(char *data)
{
    uint8_t i=0;
    while(data[i])
        WriteLCDByte(data[i++]);
}

Can anybody explain to me why

Code: [Select]
WriteLCDString((char*) "Test");
..doesn't seem to work?  For whatever reason it seems like the while(data[ i ]) loop never evaluates as true, and so no data is sent.  I have tried making it a do while loop in order to force it to transmit, and it does, but its garbage data.

The function WriteLCDByte(uint8_t)  works just fine on it own for sending individual characters.  My issue is apparently in the use of the pointer.  Any ideas?

 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 6464
  • Country: nz
Re: (Possibly) A simple pointer question
« Reply #1 on: June 05, 2017, 05:32:30 pm »
That's perfectly fine C and works for me on a PC and Raspberry Pi, after adding:

Code: [Select]
#include "stdio.h"
#include <stdint.h>

void WriteLCDByte(char b){
    putchar(b);
}

However that cast to (char*) is a bad idea. What you should be doing is void "WriteLCDString(const char *data)"
 

Offline TNorthover

  • Contributor
  • Posts: 42
  • Country: us
Re: (Possibly) A simple pointer question
« Reply #2 on: June 05, 2017, 05:38:40 pm »
There's nothing intrinsically wrong with that.

What platform are you using and how are you producing your binary? If you're using hand-written linker scripts or some equivalent it'd be semi-easy to accidentally leave the string out of the final binary. Then the CPU might read 0s from where it expects it to be.
 

Offline klr5205Topic starter

  • Regular Contributor
  • *
  • Posts: 115
  • Country: us
Re: (Possibly) A simple pointer question
« Reply #3 on: June 05, 2017, 07:27:34 pm »
I'm using MPLABX v3.60 for my IDE and the XC8 compiler and linker.

This one has me fairly stumped at the moment... must be some "trap for young players" I'm overlooking!
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1918
  • Country: se
Re: (Possibly) A simple pointer question
« Reply #4 on: June 06, 2017, 09:29:49 am »
However that cast to (char*) is a bad idea. What you should be doing is void "WriteLCDString(const char *data)"
With a C standard compliant compiler, the cast would just be redundant (not good style, though).
A string literal decays to type char* in this context; from the C99 standard, 6.4.5 String Literals:
Quote
The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For character string literals, the array elements have type char, and are initialized with the individual bytes of the multibyte character sequence;

Of course, albeit a char*, modifying the contents is not OK:
Quote
If the program attempts to modify such an array, the behavior is undefined.

In C++ instead, string literals are actually arrays of const char: trap for young and old players...

BUT from the XC8 user manual we learn (5.4.6.3):
Quote
The type of string constants is const char * and the character that make up the string are stored in the program memory, as are all objects qualified const.

 :rant: Saying that the type of string constant is const char * is plain wrong: it's an array, and it will yield a pointer unless used as argument of & or sizeof, or used to initialize another array! :palm:

And the PICs (AFAICS, I'm definitely not into them...) have different type of pointers for code (where const are stored) and data memory.
The compiler should be able to sort it out by itself and do the magic without the user noticing, but maybe in this case (possibly due to the cast) it's not.

tl,dr: Probably brucehoult is psychic, as he gave good advice before knowing XC8 vagaries were involved... :o
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3671
  • Country: gb
Re: (Possibly) A simple pointer question
« Reply #5 on: June 06, 2017, 10:13:39 am »
:rant: Saying that the type of string constant is const char * is plain wrong: it's an array, and it will yield a pointer unless used as argument of & or sizeof, or used to initialize another array! :palm:

And the PICs (AFAICS, I'm definitely not into them...) have different type of pointers for code (where const are stored) and data memory.
The compiler should be able to sort it out by itself and do the magic without the user noticing, but maybe in this case (possibly due to the cast) it's not.

The XC8 compiler puts const data into program memory, so a literal string must be referenced via a pointer of type const char * (or const x[]).

It's been a long time since I used this compiler (it was owned by HiTech back then) but IIRC a pointer to const char* can access data in either program or data memory, but a pointer of type char * can only access data memory.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 6464
  • Country: nz
Re: (Possibly) A simple pointer question
« Reply #6 on: June 06, 2017, 10:24:02 am »
tl,dr: Probably brucehoult is psychic, as he gave good advice before knowing XC8 vagaries were involved... :o

Nice. I haven't come across XC8 before. "char*" and "const char*" refer to different address spaces! Ouch. On AVR you tend to have to explicitly put __progmem__ explicitly on a variable to have it kept read-only in flash. Otherwise it's automagically copied into your (usually much smaller) RAM on program startup.

On my HiFive1 board code executes from flash, and there is an instruction cache but not a data cache. So if you accidentally have data loads from program space in your inner loop, instead of copying it to SRAM at startup (as happens automatically if the compiler thinks it's not const), it works but is 100x slower.

It's certainly hard to give good advice when people don't state what platform they're using! But type safety and a minimum of explicit casting is always a good idea.
 

Offline klr5205Topic starter

  • Regular Contributor
  • *
  • Posts: 115
  • Country: us
Re: (Possibly) A simple pointer question
« Reply #7 on: June 06, 2017, 01:10:44 pm »
Hmm, I tried initializing an array and passing it to WriteLCDString like so:

Code: [Select]
const char word[] = {'T','e','s','t'};   
    WriteLCDString(*word);

And it will print out the same nonsense as when I had forced it to print with the do while loop before.  What's interesting to me is the fact that it doesn't seem to matter what the array contains, and regardless of its size, it always prints out the same character (looks like a greek alpha) followed by 4 blanks.  Can that be any sort of a clue?
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 13125
  • Country: us
Re: (Possibly) A simple pointer question
« Reply #8 on: June 06, 2017, 01:16:58 pm »
What happens if you try the following?

Code: [Select]
const char word[] = {'T','e','s','t'};   
    WriteLCDString(word);
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 13125
  • Country: us
Re: (Possibly) A simple pointer question
« Reply #9 on: June 06, 2017, 01:21:45 pm »
I'm not much of a programmer, so I was hoping someone could point me in the right direction as far as what's probably going wrong here....

If I have this function:
Code: [Select]
void WriteLCDString(char *data)
{
    uint8_t i=0;
    while(data[i])
        WriteLCDByte(data[i++]);
}

Can anybody explain to me why

Code: [Select]
WriteLCDString((char*) "Test");
..doesn't seem to work?

I don't know why it doesn't work, but this would be better style. Does it work any differently?

Code: [Select]
void WriteLCDString(char *data)
{
    while(*data)
        WriteLCDByte(*data++);
}

Code: [Select]
WriteLCDString("Test");
 

Offline klr5205Topic starter

  • Regular Contributor
  • *
  • Posts: 115
  • Country: us
Re: (Possibly) A simple pointer question
« Reply #10 on: June 06, 2017, 01:33:10 pm »
In both of those examples the result is the same, which is to say that nothing is printed.   :-//

Is there anything useful I can do from a debug standpoint?
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3921
  • Country: it
Re: (Possibly) A simple pointer question
« Reply #11 on: June 06, 2017, 02:02:41 pm »
if you single-step and add "data" to the watch window... what do you see after you enter the function?
Code: [Select]
WriteLCDString((char*) "Test");
it's not much help but this kind of prototype and this kind of call (but without the explicit cast) is working under XC16

at the very least you should see "T" or the address where "T" is.. and in the memory window you should see "T" at the address
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 6464
  • Country: nz
Re: (Possibly) A simple pointer question
« Reply #12 on: June 06, 2017, 02:28:59 pm »
Hmm, I tried initializing an array and passing it to WriteLCDString like so:

Code: [Select]
const char word[] = {'T','e','s','t'};   
    WriteLCDString(*word);

And it will print out the same nonsense as when I had forced it to print with the do while loop before.  What's interesting to me is the fact that it doesn't seem to matter what the array contains, and regardless of its size, it always prints out the same character (looks like a greek alpha) followed by 4 blanks.  Can that be any sort of a clue?

I don't even know how that compiles, since WriteLCDString wants a char* and you're now giving it a char!

Definitely get rid of the *. And based on earlier discussion I'd try getting rid of the const too, unless perhaps WriteLCDString is declared to take a const. In which case, try getting rid of *both* consts as well.
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 10091
  • Country: us
Re: (Possibly) A simple pointer question
« Reply #13 on: June 06, 2017, 02:31:41 pm »
I would add a break to WriteLCDByte() and see what is coming in.  Is it a proven fact that WriteLCDByte() works?

As an aside, I don't always have a practical debugger and I really don't want to use printf() if the library brings along a heap requirement.  So, for every uC project, the first thing I do is get the serial port working.  Then I copy the various string/conversion functions from "The C Programming Language".  Once I can send strings and hexified bytes, shorts and ints, I can get down to the real work.
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1918
  • Country: se
Re: (Possibly) A simple pointer question
« Reply #14 on: June 06, 2017, 02:44:50 pm »
Hmm, I tried initializing an array and passing it to WriteLCDString like so:

Code: [Select]
const char word[] = {'T','e','s','t'};   
    WriteLCDString(*word);
Well, this code contains two faults:
  • When one initializes a string in that way, the terminating zero valued character cannot be omitted:
Code: [Select]
const char word[] = {'T','e','s','t','\0'};
  • The function expects a pointer to char (or a pointer to const char?) but in the code *word is used: word, being an array, decays to a pointer and the * operator takes the content of object pointed to. In this case, 'T' is passed.(Ninjaed by brucehoult...)

The compiler should vigorously complain when it sees a single char instead of a pointer, though, unless there's an explicit cast (don't do that)

Are you perchance using a PIC18F24/..K40?
Search NVMREG in the errata linked above, and see here for a workaround.

Unfortunately I can't help much more, as I just have google but no PICs...

Edit: clarity.
« Last Edit: June 06, 2017, 02:59:40 pm by newbrain »
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline klr5205Topic starter

  • Regular Contributor
  • *
  • Posts: 115
  • Country: us
Re: (Possibly) A simple pointer question
« Reply #15 on: June 06, 2017, 03:05:15 pm »
I would add a break to WriteLCDByte() and see what is coming in.  Is it a proven fact that WriteLCDByte() works?

Yes I can write messages on the LCD one letter a time using WriteLCDByte(); it is working as expected.

If I single step through the program, once the program enters WriteLCDString(), *data = 'T'; 0x54

However, it exits the function without ever going to WriteLCDByte(), meaning while(data) was false for some reason, which doesn't make sense to me
 

Offline klr5205Topic starter

  • Regular Contributor
  • *
  • Posts: 115
  • Country: us
Re: (Possibly) A simple pointer question
« Reply #16 on: June 06, 2017, 03:15:42 pm »
Hmm, I tried initializing an array and passing it to WriteLCDString like so:

Code: [Select]
const char word[] = {'T','e','s','t'};   
    WriteLCDString(*word);
Well, this code contains two faults:
  • When one initializes a string in that way, the terminating zero valued character cannot be omitted:
Code: [Select]
const char word[] = {'T','e','s','t','\0'};
  • The function expects a pointer to char (or a pointer to const char?) but in the code *word is used: word, being an array, decays to a pointer and the * operator takes the content of object pointed to. In this case, 'T' is passed.(Ninjaed by brucehoult...)

The compiler should vigorously complain when it sees a single char instead of a pointer, though, unless there's an explicit cast (don't do that)

Are you perchance using a PIC18F24/..K40?
Search NVMREG in the errata linked above, and see here for a workaround.

Unfortunately I can't help much more, as I just have google but no PICs...

Edit: clarity.

I'm using a PIC18F27K40, however that section of the errata states that all PIC18F__K40 devices suffer from the issue they describe. That may well be it; I'll report back once I have a chance to test.
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3921
  • Country: it
Re: (Possibly) A simple pointer question
« Reply #17 on: June 06, 2017, 04:28:50 pm »
Solved in A4 silicon revision. you know which is it when the programmer read the device ID

i again suggest you single step with the debugger

also, simulator should be able to run the code so one doesn't need the physical chip to test (and testing should be faster too)
 

Offline klr5205Topic starter

  • Regular Contributor
  • *
  • Posts: 115
  • Country: us
Re: (Possibly) A simple pointer question
« Reply #18 on: June 06, 2017, 08:19:25 pm »
That was it!  My device is revision A2 so the workaround described in the link above was applicable.

Thanks to everyone especially newbrain for your help!

 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1918
  • Country: se
Re: (Possibly) A simple pointer question
« Reply #19 on: June 06, 2017, 08:38:19 pm »
You are welcome!
Glad to see it solved. :-+

Always check for errata.
I was, e.g., bitten by this bug in STM32F746:
"Missed ADC triggers from TIM1/TIM8, TIM2/TIM5/TIM4/TIM6/TRGO or TGRO2 event"
and lost some hours before doing my homework and enabling the DAC clock. :blah:

Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 6464
  • Country: nz
Re: (Possibly) A simple pointer question
« Reply #20 on: June 07, 2017, 09:29:24 am »
Are you perchance using a PIC18F24/..K40?
Search NVMREG in the errata linked above, and see here for a workaround.

Ugh.

So, as I suggested, it was a problem reading data from program memory, and (as I also suggested several times) getting rid of the "const" on the declaration of "word" should also have worked around the problem.

Well, assuming the startup code in the runtime library that copies writable initialised data from ROM to RAM was not similarly affected by the chip errata, which may or may not be the case.
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1918
  • Country: se
Re: (Possibly) A simple pointer question
« Reply #21 on: June 07, 2017, 10:26:33 am »
So, as I suggested, it was a problem reading data from program memory, and (as I also suggested several times) getting rid of the "const" on the declaration of "word" should also have worked around the problem.

Well, assuming the startup code in the runtime library that copies writable initialised data from ROM to RAM was not similarly affected by the chip errata, which may or may not be the case.
Eh..probably not, the startup code and the compiled one apparently use a table access instruction that does not work without the workaround.
So there's almost no sane way to initialize a string, as the compiler uses const char for string literals (against the standard), apart from assigning one char element at the time.
At least, that's my understanding, but I might very well be wrong  :-//
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline NivagSwerdna

  • Super Contributor
  • ***
  • Posts: 2571
  • Country: gb
Re: (Possibly) A simple pointer question
« Reply #22 on: June 07, 2017, 11:23:42 am »
Are you perchance using a PIC18F24/..K40?
Search NVMREG in the errata linked above, and see here for a workaround.
OOooo.. that's brutal. Very useful info newbrain.  :clap:
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

- - -
-->