Sap*_*Sap 7 c++ gcc strict-aliasing c++11
该计划 - 某种旧式网络消息传递:
// Common header for all network messages.
struct __attribute__((packed)) MsgHeader {
uint32_t msgType;
};
// One of network messages.
struct __attribute__((packed)) Msg1 {
MsgHeader header;
uint32_t field1;
};
// Network receive buffer.
uint8_t rxBuffer[MAX_MSG_SIZE];
// Receive handler. The received message is already in the rxBuffer.
void onRxMessage() {
// Detect message type
if ( ((const MsgHeader*)rxBuffer)->msgType == MESSAGE1 ) { // Breaks strict-aliasing!
// Process Msg1 message.
const Msg1* msg1 = (const Msg1*)rxBuffer;
if ( msg1->field1 == 0 ) { // Breaks strict-aliasing!
// Some code here;
}
return;
}
// Process other message types.
}
Run Code Online (Sandbox Code Playgroud)
此代码违反了现代GCC中的严格别名(并归结为现代C++中未指定的行为).解决问题的正确方法是什么(使代码不会引发"严格别名"警告)?
PS如果rxBuffer定义为:
union __attribute__((packed)) {
uint8_t[MAX_MSG_SIZE] rawData;
} rxBuffer;
Run Code Online (Sandbox Code Playgroud)
然后我将&rxBuffer转换为其他指针它不会引起任何警告.但它是安全,正确和便携的方式吗?
定义rxBuffer为一个指向union的uint8_t[MAX_SIZE],MsgHeader,Msg1和任何类型的你打算投给.请注意,这仍然会破坏严格的别名规则,但在GCC中它保证可以作为非标准扩展.
编辑:如果这样的方法会导致过于复杂的声明,那么完全可移植(如果较慢)的方法是将缓冲区保持为简单状态uint8_t[],memcpy并在必须重新解释时立即将其保存到适当的消息结构中.这种方法的可行性显然取决于您的性能和效率需求.
编辑2:第三种解决方案(如果您正在研究"正常"架构)是使用无效,因为转换为消息类型可能不起作用,请参见此处char或unsigned char代替uint8_t.这些类型保证为所有内容添加别名.