ckeiluint16

Getting uint16_t value from uint8_t array in Keil


I am trying get variables from UART packet without using "<<" operator.

uint8_t buffer[8] = {0x11,0x22,0x33,0x44};
uint16_t val = *((uint16_t *)buffer);

If I try the code above in keil it is working. When I try it for the array in struct compiler doesn't give error but it goes to hardfault handler during runtime.

typedef struct
{
  uint8_t address;
  uint8_t opID; 
  uint8_t dataLen;
  uint8_t data[250];
  uint8_t crc[2];
}MODBUS;

MODBUS receivedData;
uint16_t val = *((uint16_t *)receivedData.data);

I also tried this(array in struct) in online c compiler. It is working without any problem. What should I do to use same thing in keil?


Solution

  • *((uint16_t *)buffer); has two undefined behavior bugs:

    Additionally, you also have the potential problem that network endianess of the UART protocol might not match CPU endianess. What is CPU endianness? Most UART protocols use Big Endian.

    To solve this, you could use memcpy as mentioned in another answer. Or more efficiently, a wrapper union:

    typedef union
    {
      uint8_t  u8  [8];
      uint16_t u16 [4];
    } uart_buf_t;
    

    This solves misalignment and strict aliasing both, but it will not solve potentially mismatching endianess. To solve that, you need to use bit shifts instead.