clanguage-lawyerplatform-agnostic

What is the safest cross-platform way to get the address of a byte in a word?


The following sets byte to 1 on big-endian and 0 on little-endian.

uint16_t word = 0x0001;
uint8_t byte = *(((uint8_t *)&word) + 1);

Is there any way to get the address of the low or high byte that is cross-platform safe?


Solution

  • Since C99, code could use a compound literal to find the MSByte address offset.
    Let the compiler form efficient code.

    Below uses a 4-byte example to help illustrate adherence with big, little and PDP endian.

    int main() {
      uint32_t word = 0x12345678;
      printf("%p\n", (void*)&word);
      for (unsigned i=0; i<sizeof word; i++) printf("%x\n", ((uint8_t*) &word)[i]);
    
      uint8_t *msbyte_address = ((uint8_t*) &word) + //
      //  v----------------------------------------------------v compound literal
          ( union { uint32_t u32; uint8_t u8[4]; }) {0x00010203}.u8[0];
      //                                    value at 1st byte    ^---^
    
      printf("%p\n", (void*)msbyte_address);
    }
    

    Example output (little endian)

    0xffffcbfc
    78
    56
    34
    12
    0xffffcbff
    

    For uint16_t

      uint16_t word = 0x1234;
      uint8_t *msbyte_address = ((uint8_t*) &word) + 
          ( union { uint16_t u16; uint8_t u8[2]; }) {0x0001}.u8[0];