Martin
Martin

Reputation:

Simple C char question

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?

Upvotes: 0

Views: 662

Answers (5)

paxdiablo
paxdiablo

Reputation: 881443

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.

Upvotes: 6

Binary Worrier
Binary Worrier

Reputation: 51711

"\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.

Upvotes: 1

OneOfOne
OneOfOne

Reputation: 99234

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.

Upvotes: 2

EFraim
EFraim

Reputation: 13028

  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.

Upvotes: 0

sharptooth
sharptooth

Reputation: 170499

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,

Upvotes: 4

Related Questions