Search code examples
cpointerscasting

How to dereference and autoincrement a cast pointer in C?


I have a void* in plain C that I'm using while walking through some unstructured data, and I'd like to cast with dereference and autoincrement as I go. I would like to write the following:

void* ptr = /*something*/;
uint16_t i = *((uint16_t*) ptr)++;

The compiler objects and tells me "lvalue required as increment operand", but I guess I thought that a pointer cast as a pointer would still qualify as an lvalue.

Clearly my intent is for ptr to now point two bytes beyond where it pointed before. I can't remove the parentheses around the cast of ptr because ++ has higher precedence than the cast, so this won't work as I want it to:

int i = *(uint16_t*) ptr++;

I could of course do my own incrementing, like the following, but I was hoping for something elegant and concise:

int i = *(uint16_t) ptr;
ptr += sizeof(uint16_t);

What's a good way to do this?


Solution

  • Incrementing a pointer cast to a different type has been disallowed for a long time, probably since C89. The reason is that the conversion from one type of pointer to another type can change the representation, and thus might not refer to the same object.

    You must split the expression into 2 statements:

    void *ptr = /*something*/;
    uint16_t i = *(uint16_t*)ptr;
    ptr = (uint16_t*)ptr + 1;
    

    Or if context commands for a single expression, you could use this hack:

    uint16_t i = ((uint16_t*)(ptr = (uint16_t*)ptr + 1))[-1];
    

    Or this one if you want to obfuscate even more:

    uint16_t i = (-1)[(uint16_t*)(ptr = (uint16_t*)ptr + 1)];