2

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.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
  • 1
    "you add the size of the pointer instead" --> Not quite. Code adds the size of the pointed to object. – chux - Reinstate Monica Mar 29 '19 at 14:13
  • Better: when you add `1` to a pointer `p`, you increment it by the size of the type it points to, with respect to `p`'s type in the expression. – ergysdo Mar 29 '19 at 14:18
  • When you access the memory like this, you must be aware that the host has the same endianness as the emulated machine AND that the host allows unaligned memory access. Otherwise you'll have to access the memory the complicated way, anyway! – Martin Rosenau Mar 29 '19 at 14:20
  • 2
    *`bc` is the name of an `int16_t *` type. It's a pointer to a combination of two `int8_t`'s.* That sounds like a [strict aliasing](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) violation. You can't safely take an object of one type and treat it like another type. In this case, you can't assume that two `int8_t` values can be safely accessed as an `int16_t` value, even if the two `int8_t` values are adjacent in memory. – Andrew Henle Mar 29 '19 at 14:21
  • Yeah. I have a little function called `bswap16` that does this for me. Thanks for all the feedback! – S.S. Anne Mar 29 '19 at 14:22
  • 2
    Heed @AndrewHenle 's warning. You seem to be wading into dangerous territory here. – Christian Gibbons Mar 29 '19 at 14:23
  • @AndrewHenle They're objects in a `struct`, so it should be safe. It's also the only possible way to emulate the behavior of the Z80 directly. – S.S. Anne Mar 29 '19 at 14:24
  • 3
    Being objects in a struct does not absolve you of strict aliasing violations. If you want to get around it, you can use unions to type-pun. – Christian Gibbons Mar 29 '19 at 14:26
  • Would an array be able to work around this? – S.S. Anne Mar 29 '19 at 14:28
  • 3
    @JL2210 You should write probably a new question about how to type-pun and include code that shows how you are doing it and we can go into greater details rather than going off on a tangent in this question. You could leave a reference to this question mentioning that the new one is a follow up to this. – Christian Gibbons Mar 29 '19 at 14:31

2 Answers2

3

(((intptr_t)bc)+sp) is equivalent 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.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
2

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.

armitus
  • 712
  • 5
  • 20
  • Sorry for unaccepting an answer but almost a year later I realize that the other answer is better advice. – S.S. Anne Jan 11 '20 at 02:08