Cast increment and assign in C


How can I achieve the following? De-reference and assign a value to a pointer and increment the pointer by (uint64_t) bytes in one line.

// random address 0xDEADBEEF
unsigned int *myvalue = 0xDEADBEEF;
*((uint64_t*) myvalue)++ = 34;

An error is produced due to the casting if i remove the casting then it "works" but not with the results which I want.

unsigned int *myvalue = 0xDEADBEEF;
*(myvalue)++ = 34;

What I expect by the statement of :

// myvalue points to 0xDEADBEEF
*((uint64_t*) myvalue)++ = 34;
 //myvalue points to 0xDEADBEEF + (64/8)
 // at 0xDEADBEEF (a random address) should contain 34
asked on Stack Overflow Jun 28, 2016 by Har • edited Jun 28, 2016 by Har

4 Answers


[How can I] De-reference and assign a value to a pointer and increment the pointer by (uint64_t) bytes in one line[?]

You are trying to do too many things with a single expression. You should break it up. Moreover, "one line" is more or less arbitrary. I could take your one-liner and spread it out over 12 non-empty lines, and I can take many lines and join them together. The closest actually meaningful thing would be one full expression.

Nevertheless, if you insist on doing it in one full expression, and you're willing to assume that the size of an int evenly divides the size of a uint64_t, then you might do it like so:

unsigned int *myvalue = 0xDEADBEEF;
*myvalue = 34, myvalue += (sizeof(uint64_t) / sizeof(int));

Of course, that's mostly sophistry around the meaning of a "full expression" -- it would be much better style to use a semicolon instead of a comma operator, but then there would be two full expressions. But that's the ground on which you chose to pitch your tent.

Alternatively, if you're open to changing the type of myvalue, then it would be a bit cleaner to do it like this:

uint64_t *myvalue = 0xDEADBEEF;
* (int *) (myvalue++) = 34;

Overall, however, although C permits casting from one object pointer type to another, it makes few promises about how the converted result can safely be used. Furthermore, such casts violate the strict aliasing rule, which may contribute to an optimizing compiler producing an incorrect and hard-to-debug program.

answered on Stack Overflow Jun 28, 2016 by John Bollinger

So the subject of an increment operator needs to be a modifiable lvalue.

Your expression ceases to be an lvalue when you cast it.

Now, you can increment the result of the dereference with something like *(*x)++ ... for example, this is conforming...

int f(int **x)
  return *(*x)++;
answered on Stack Overflow Jun 28, 2016 by DigitalRoss • edited Jun 28, 2016 by DigitalRoss

You could write *(*(uint64_t**) &myvalue)++ = 34;, but why would you do that?

Above line works because casting yields a rvalue, i.e. can only be on the right of an assignment (the assignment here is the ++), and dereference yields a lvalue (which can be on the left).

Also, as noted by others, dereferencing your casted pointer is undefined behavior.

answered on Stack Overflow Jun 28, 2016 by a3f • edited Jun 28, 2016 by a3f

Casting an unsigned int* to a uint64_t* and then dereferencing the uint64_t* is wrong by itself.

Disregarding that fact for a moment...

Due to operator precedence,

*((uint64_t*) myvalue)++ = 34;

is equivalent to:

*(((uint64_t*) myvalue)++) = 34;

i.e. it increments the pointer first before dereferencing it.

When you use a cast, you get an rvalue. You cannot increment or decrement an rvalue.

Also, it's not clear why you want to increment the temporary pointer obtained from the cast in the first place. Unless you have a variable that you want to use afterward, it is pointless to increment or decrement a pointer.

answered on Stack Overflow Jun 28, 2016 by R Sahu • edited Jun 28, 2016 by R Sahu

User contributions licensed under CC BY-SA 3.0