tags:

views:

189

answers:

5

Hi

Consider the following simple code fragement:

void SetCommand( const unsigned char *cmd )    
{
    iHeader[4] = *cmd;
}

...

const unsigned char *test = "\x72";  
unsigned char iHeader[32];  

hdrSetCommand(test);

What I wanna do is pretty straighforward: I have a 32 character array and the SetCommand should set me the 4th byte to "\x72". The code as it is here works fine, but what I do not understand is why I do have to write

 iHeader[4] = *cmd /* instead of */ iHeader[4] = cmd ?

And furthermore, when declaring

unsigned char *test = "\x72";

I also get an error message that test needs to be declared as constant? How come?

+5  A: 

You need *cmd because in order to retrieve the char value you need to dereference the char* pointer and that requires using the * operator.

You need to declare test as const because you make it point to a constant string literal - assigning an address of a constant literal to a pointer to non-const (char*, not const char*) violates const-correctness and is prohibited,

sharptooth
Thanks for your answers, and what happends if I wanna make changes to the string literal? Maybe just changeing single bits of test with some bitmasks? I cant do that when it is constant
You're not allowed to - it's undefined behaviour. Usually the program will crash because of writing to a read-only segment of memory. You need to allocate a separate buffer, copy the string there and change the copy.
sharptooth
Makes sense, thank you
A: 
  1. Because you are passing a pointer to character string, not a single character. *cmd dereferences the first character in the array.

  2. Because static strings are in a read-only data segment. Thus any pointers to them should be read only.

EFraim
+2  A: 

Should be something along the lines of :

void SetCommand( unsigned char cmd ) {
   iHeader[4] = cmd;
}

const unsigned char test = '\x72';  
unsigned char iHeader[32];

you're trying to assign a point to a single byte, which won't work.

OneOfOne
+7  A: 

Because cmd is a pointer. It points to the actual characters in memory and it's likely to be a weird value like 0xbf001234. The following diagram may illustrate:

Memory address
            +------------------+
0xef001214: | cmd (0xbf001234) |
(on stack)  +------------------+
               |                 +----+----+
0xbf001234:    +---------------> |\x72|\x00|
(in read-only                    +----+----+
       memory)

When you de-reference cmd (with *cmd), it actually gets the character at the memory location where cmd points to, which is the \x72 that you want. The basic difference is:

  • "\x72" is a pointer to a constant char array { '\x72', '\0' }.
  • '\x72' is the single character.

What you were probably looking for was something along the lines of:

#define CMD_POS 4
#define CMD_TEST '\x72'
...
unsigned char iHeader[32];  
void hdrSetCommand (unsigned char cmd) {
    iHeader[CMD_POS] = cmd;
}
...
unsigned char test = CMD_TEST;  
hdrSetCommand (test);

This passes the character '\x72' rather than a pointer to the string containing that character.

Also note the judicious use of #defines - these usually make the code a lot more readable and less prone to errors (since, for example, CMD_POS is only defined at one point rather than scattered throughout the code as the magic number 4). You should look carefully at the use of all magic numbers other than zero or one.

As to the reason why you got the error stating that your string variable needs to be defined constant, this is because you cannot change the contents of a const char array (which is what "\x72" is, a two-element character array) - the compiler is free to place it into read-only memory and/or share it such as the two strings:

const char *x = "Hello there";
const char *y = "there";

being allowed to overlap as follows:

Memory location
                +---+---+---+---+---+---------+
0xbf005678 (x): | H | e | l | l | o | <space> |
                +---+---+---+---+---+---------+
0xbf00567e (y): | t | h | e | r | e |   \0    |
                +---+---+---+---+---+---------+

By attempting to treat a constant string as non-constant, you break your contract with the compiler.

paxdiablo
+1  A: 

"\x72" is a string, therefore you need a pointer to point to all the characters in that string, so after

const unsigned char *test = "\x72";

test points to the frist of two characters '\x72' and a null terminator '\x0'

You can rewrite this as

const unsigned char test = '\x72';

test is now a character, and you can then write your function as

void SetCommand( const unsigned char cmd )    
{    
    iHeader[4] = cmd;
}

You no longer need *cmd, because cmd is not a pointer, therefore you do not need to dereference it to get it's value

Hope this helps.

Binary Worrier