Приведение char[] к ussigned int дает: разыменование указателя с типизированным типом нарушит строгие правила сглаживания

У меня есть строка в исходном коде некоторого наследия:

#define MAXMSG 1024
...
char m_recvBuf[MAXMSG];
unsigned int msgLength = ntohl(*((unsigned int *)m_recvBuf));

Это дает следующее предупреждение:

x.cpp: In member function ‘bool xx::cccc(std::string&)’:
x.cpp:308: warning: dereferencing type-punned pointer will break strict-aliasing rules

Как я могу избавиться от этого предупреждения?

моя строка компиляции:

g++ -c -g -O2 -Wall -DDEBUG_ON -D_VERSION_=\"1.0.0\" `xml2-config --cflags` -I../src -I./common -I. -I../../test/ -o common/xx.o common/xx.cpp

$ g++ --version
g++ (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3)

person Patryk    schedule 28.08.2014    source источник
comment
@МаркоА. Пожалуйста, проверьте мое обновление   -  person Patryk    schedule 28.08.2014
comment
Используйте параметр компилятора -fno-strict-aliasing. Этот код нарушает стандарт, и в режиме -O3 gcc может полностью оптимизировать его, однако параметр -fno-strict-aliasing заставляет его вести себя так, как будто вы хотите получить доступ к памяти в буфере char.   -  person M.M    schedule 28.08.2014
comment
Вы также можете рассмотреть возможность исправления кода, например. unsigned int msgLength; memcpy(&msgLength, m_recvBuf, sizeof msgLength); msgLength = ntohl(msgLength);, а еще лучше сделать переносную конвертацию   -  person M.M    schedule 28.08.2014


Ответы (2)


Проблема с вашим кодом в том, что он нарушает строгие правила псевдонимов и поэтому потенциально небезопасны.

Вы можете скрыть предупреждение с помощью -Wno-strict-aliasing (это не решит вашу проблему), изменить структуру данных или полностью избежать проблемы, указав положение и длину вашей двоичной копии, как предложил Мэтт (вероятно, лучший вариант):

unsigned int msgLength; 
memcpy(&msgLength, m_recvBuf, sizeof(msgLength)); 
msgLength = ntohl(msgLength);

Примечание: я не получал ошибку с clang 3.4 и gcc 4.8.2 в -O3, это означает, что компилятор мог оптимизировать предупреждение. В любом случае это не гарантирует, что ваш код безопасен.

person Marco A.    schedule 28.08.2014
comment
Лично я предпочитаю эту статью о строгом использовании псевдонимов, чем QT один. - person Shafik Yaghmour; 28.08.2014
comment
Также обратите внимание, как я упоминаю в своем ответе здесь, строгие проверки псевдонимов не гарантируют обнаружение нарушений строгого псевдонима. Так что отсутствие предупреждения ничего не значит. - person Shafik Yaghmour; 28.08.2014

Как сказали предыдущие ответчики, вы можете изменить флаги компиляции, чтобы предупреждение исчезло. Однако, если вы готовы к небольшому легкому рефакторингу, вы можете решить проблему более аккуратно с помощью такого объединения:

#define MAXMSG 1024

union {
  char buf[MAXMSG];
  unsigned int length;
} recvbuf;

// [ read your message stream to recvbuf.buf ]

unsigned int msgLength = ntohl(recvbuf.length);
person Andy Brown    schedule 28.08.2014
comment
Обратите внимание, что каламбур типов через объединение является технически неопределенным поведением в C++, но большинство компиляторов поддерживают его. Вы можете узнать больше в моем ответе здесь. - person Shafik Yaghmour; 28.08.2014