Search code examples
cpointersunsigned-integerunsigned-char

Pointer to different data type in C


I have compiled and run the following program in C:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(int argc, char* argv[]){
  uint8_t data[8] = {0, 1, 2, 3, 4, 5, 6, 7};
  uint32_t* pointer32 = &data[0];
  uint64_t* pointer64 = &data[0];

  printf("%" PRIu64 "\n", *pointer64);
  printf("%" PRIu32 "\n", *(pointer32++));
  printf("%" PRIu32 "\n", *pointer32);

  return 0;
}

and received the following expected output:

506097522914230528
50462976
117835012

The output is correct and corresponds to the bitwise interpretation of the data as an unsigned 64-bit integer and unsigned 32-bit integers. I tried this on a 64-bit machine running Ubuntu 14.04. It was compiled with the stock gcc compiler (4.8.4?). The compiler does throw the "assignment from incompatible pointer type" warning (which can be safely ignored because the incompatible assignment is intended).

Is this a reliable way of converting and interpreting the data in the "data" array, or would it be better recommended to manually copy and shift each byte, one at a time, to a temporary variable?


Solution

  • You are violating aliasing rules. So, the clear answer is: no.

    Briefly: you must not have pointers of different type pointing to the same object. This may result in broken code, as the compiler actually does assume this does not happen and might optimize the code.

    Just a very strong hint: do not ignore warnings. They are given for good reasons.

    The best way is to properly serialize/deserialize the data from the array per element to the final types. This will also avoid any problems with endianess (byte-ordering) of the values and any (possible) padding.

    I use functions like this:

    uint32_t readUInt32(const uint8_t **buffer)
    {
        ... // increment buffer accordingly
    }
    

    This way, I just pass the buffer pointer along the line, without having to care about incrementing in the caller. The technic is actually an iterator.