Программирование AVR: решение проблем, FAQ Как избавиться от предупреждения о нарушении типизации? Tue, December 12 2017  

Поделиться

нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


Как избавиться от предупреждения о нарушении типизации? Печать
Добавил(а) microsin   

Вот 2 простых примера, когда компилятор GCC сообщает предупреждением о нарушении строгой типизации языка C (warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]):

unsigned int received_size = ntohl (*((unsigned int*)dcc->incoming_buf));
*((unsigned int*)dcc->outgoing_buf) = htonl (dcc->file_confirm_offset);

Здесь буферы incoming_buf и outgoing_buf определены так:

char incoming_buf[LIBIRC_DCC_BUFFER_SIZE];
char outgoing_buf[LIBIRC_DCC_BUFFER_SIZE];

Предупреждение компилятора понятно, и он прав. Чтобы избежать ошибок и неожиданного поведения программы, нужно в обоих частях оператора присваивания использовать совместимые типы, и не использовать такое грубое приведение типов. Конечно, решить проблему можно, отключив опциями выдачу предупреждения, но такой способ не очень хорош. Лучше решить проблему без нарушения четкой проверки типов.

Первое, что следует сделать - выяснить причину, почему пришлось применить приведение типов с нарушением, и попытаться устранить проблему, применив те типы, которые нужны.

[Грубый способ: переопределение массива]

Если есть лишняя память, то можно определить массивы как unsigned int, и выполнять присваивание переменной типа char без появления предупреждения. Пример:

unsigned int incoming_buf[LIBIRC_DCC_BUFFER_SIZE / sizeof (unsigned int)];
unsigned int outgoing_buf[LIBIRC_DCC_BUFFER_SIZE / sizeof (unsigned int)];

Примечание: из-за того, что размер unsigned int зависит от используемой платформы, необходимо это учитывать в программе. Например, когда подразумевается использование 32-битного числа, можно вместо unsigned int явно указать тип uint32_t.

Теперь можно хранить значения типа char в массиве как число int, и выполнять присваивание без появления предупреждения о нарушении строгой типизации:

*((char *) outgoing_buf) = переменная_типа_char;

или

переменная_типа_char = *((char *) incoming_buf);

[Функции преобразования порядка байт]

Иногда необходимо данные в неком байтовом буфере интерпретировать по-разному. Например, это могут быть байты, но нам требуется собрать из них 16-битное число. Для нашего примера можно использовать готовую функцию ntohl, которая предназначена для использования в сетевых коммуникациях - она преобразует число типа u_long с порядком следования байт TCP/IP в порядок следования байт хоста (для процессоров Intel это порядок следования little-endian).

unsigned int received_size = ntohl (*((unsigned int*)dcc->incoming_buf));

[Использование union]

Предположим, что буфер из 2 байт иногда нужно интерпретировать как байтовый, а иногда как 16-битное число. Это может пригодиться, например, для декодирования ESC-последовательностей. Пример:

char escdata[2];

Этот маленький буфер будет использоваться в программе для накопления данных Esc-последовательности.

   //берем очередной символ из буфера
   c = rx_usb[outUsbRX++];
   outUsbRX &= RX_BUF_MASK_USB;
   //и начинаем его анализ
   if (Esc1Bstate == 1)
   {
      escdata[0] = c;
      Esc1Bstate++;
      cmdlen = 0;
      return;
   }
   else if (Esc1Bstate == 2)
   {
      escdata[1] = c;
      cmdlen = 0;
      Esc1Bstate=0;
      //тут надо анализировать массив escdata
      // и предпринимать соответствующие действия
///////////////////////////
// стрелка вверх или вниз
      //здесь GCC выдаст предупреждение "warning: dereferencing type-punned
      // pointer will break strict-aliasing rules [-Wstrict-aliasing]":
      if (0x415B == *(u16*)escdata) 
      {  
         ...

Чтобы избавиться от предупреждения, можно переопределить escdata как объединение:

static union
{
   char sym[2];
   u16  val16;
}escdata;

Теперь к буферу можно обращаться как по байтам, так и как к 16-битному числу, без появления предупреждения о нарушении строгой проверки типов.

   if (Esc1Bstate == 1)
   {
      escdata.sym[0] = c;
      ...
   }
   else if (Esc1Bstate == 2)
   {
      escdata.sym[1] = c;
      ...
      if (0x415B == escdata.val16)
      {

[Ссылки]

1. Порядок следования байт (endianness).

 

Добавить комментарий


Защитный код
Обновить

Top of Page