Функция, возвращающая указатель на массив - приведение и получение значения - PullRequest
0 голосов
/ 01 ноября 2019

У меня небольшая дилемма с моим кодом.

У меня есть функция, которая возвращает указатель (uint8_t *) на буфер данных. Возможно и законно привести этот указатель к uint16_t, когда мне нужно 2 значения из массива как uint16_t? Или будет проблема с выравниванием? Буфер заполняется через чтение байтов из I2C.

Проблема существует на MCU, но когда я пытаюсь это сделать с visualstudio, это нормально. MCU - Hardfault

uint8_t arr[8];

uint8_t * FuncReturnPointer(void)
{
     arr[0] = 0xEE;
     arr[1] = 0xFF;

     return arr;
}

main
{
     uint16_t val16 = 0;

     val16 = *(uint16_t*)FuncReturnPointer();
}

Что-то не так / опасно?

Ответы [ 2 ]

0 голосов
/ 02 ноября 2019

Здесь есть два отдельных вопроса:

  • строгое нарушение алиасинга
  • возможное нарушение выравнивания

Любой из них можетприводят к различным «интересным» явлениям. Могу поспорить, что это связано с нарушением выравнивания, т. Е. arr не находится по адресу, кратному _Alignof(uint16_t). Правильным решением является использование либо

  • арифметики:

    val16 = ((uint16_t)*address << 8) | (address);
    
  • memcpy:

    memcpy(&val16, address, sizeof (val16));
    
0 голосов
/ 01 ноября 2019
Типы

uint8_t, uint16_t, char и т. Д. В указателях фактически указывают программе, как обрабатывать значение в указанном адресе. Ваша функция "FuncReturnPointer" возвращает адрес массива "arr", который является массивом 8-битного типа. Когда вы добавляете (uint16_t *) преобразователь типов в эту функцию, то он фактически обрабатывает его как 16-битное число и сохраняет его как 0x00EE, а не 0xEE. Хорошей практикой было бы что-то вроде этого:

main
{
     uint16_t val16 = 0; 
     uint8_t *address;

     address = FuncReturnPointer();  //this gets the address of the arr
     val16 = (*(address++)<<8) + (*address);
}
...