Casting behavior in C

2019-07-31 06:55发布

问题:

I'm currently trying to avoid the pointer arithmetic workings in C to write an emulator.

Usually, if you add 1 to a pointer in C, you add the size of the pointed to object instead. However, I am trying to work with bits and bytes, so this is undesired.

I was wondering if I was using too many parentheses in this example:

*(int16_t *)(((intptr_t)bc)+sp)

And if not, then is it equivalent to this? :

*(int16_t *)((intptr_t)bc+sp)

sp is a page-aligned stack address for my emulator (obtained via. mmap without MAP_FIXED set). It is an intptr_t type.

bc is the name of an int16_t * type. It's a pointer to a combination of two int8_t's.

回答1:

What you're asking about is operator precedence. A full list can be found here.

The '+' operation occurs after a type cast operation. Therefore, you do not need the second layer of parenthesis because the intptr_t cast is applied FIRST to bc, then the result is added to sp.



回答2:

(((intptr_t)bc)+sp) is equivalent t to ((intptr_t)bc+sp).


But this whole "avoid the pointer arithmetic" approach is not portable.

At least 3 concerns:

  • Pointers, converted to an integer, do not certainly maintain the math properties needed.

    // possible outcome
    uint16_t x[2];
    printf("%llx\n", (unsigned long long) (intptr_t) &x[0]); // --> abcd0000
    printf("%llx\n", (unsigned long long) (intptr_t) &x[1]); // --> abcd0010
    

The difference as integers may be 16 and not the hoped for 2 -- even if a difference of 2 is more common.

  • Further, with *(int16_t *)((intptr_t)bc+sp), if sp is odd, (int16_t *) can fail due to alignment restrictions.

  • Anti-aliasing issues occur too. @Andrew Henle

Such avoidance of pointer arithmetic though integers has various pitfalls - good luck.