c-如何处理严格的别名警告

c-如何处理严格的别名警告,c,strict-aliasing,type-punning,C,Strict Aliasing,Type Punning,哪种方法最容易消除严格的别名警告 代码是: uint8_t msg[3]; int retval; msg[0] = (uint8_t) INT_READ_EVENT; *((uint16_t *) &msg[1]) = bytesToRead; retval = write(intPipe[1], msg, sizeof(msg)); bytesToRead作为uint16_t值传递 在另一端,有一个read,它接收一个字节来识别事件类型(本例中为INT_read_event),

哪种方法最容易消除严格的别名警告

代码是:

uint8_t msg[3];
int retval;

msg[0] = (uint8_t) INT_READ_EVENT;
*((uint16_t *) &msg[1]) = bytesToRead;

retval = write(intPipe[1], msg, sizeof(msg));
bytesToRead作为uint16_t值传递

在另一端,有一个read,它接收一个字节来识别事件类型(本例中为INT_read_event),然后再处理剩余的数据

是否有任何快速、简单的方法来消除警告:

warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
    *((uint16_t *) &msg[1]) = bytesToRead;
    ^

您可以定义一个结构来执行此操作,而不是使用字符缓冲区

struct message
{
    uint8_t code;
    uint16_t payload;
};

struct message msg;

msg.code = INT_READ_EVENT;
msg.value = bytesToRead;
在多平台/可移植代码中必须考虑对齐和端点

如果还希望以原始模式访问struct的数据,您可以:

union message_with_raw
{
    struct message msg;
    uint8_t rawdata[sizeof(struct message)];
}

这样,因为它强制您确定16位值应表示为的endianness:

// Little-endian.
msg[1] = bytesToRead & 0xff;
msg[2] = (bytesToRead >> 8) & 0xff;

对于big-endian,将右边的顺序颠倒过来。

听起来像是在解码某种协议,因此一种方法是声明与协议数据对应的结构:

typedef struct
{
  uint8_t  something;
  uint16_t bytes_to_read;
} prot_data_t;
然后,为了方便起见,为了避免别名问题,您可以将其放在一个联合中:

typedef union
{
  prot_data_t named_data;
  uint8_t     raw_data [sizeof(prot_data_t)];
} protocol_t;
现在,您可以通过
raw_data
逐字节发送/接收数据,但可以通过
named_data
访问不同的值


需要考虑的一些事项:

请记住,此代码以及任何不使用位移位的解决方案都将依赖于endianess


这样的代码可能容易受到对齐和结构/联合填充问题的攻击。为了最大限度地提高可移植性,不建议使用结构/联合,除非您将它们与一些序列化/反序列化例程结合使用。

这个警告是有原因的。如果
msg
在16位边界上启动,则
msg[1]
不会启动。因此,如果尝试从该字段的地址开始写入16位值,可能会触发对内存的无效写入陷阱,并导致崩溃

您应该一次写入一个字节。假设您希望字节采用big-endian格式(也称为网络字节顺序),则可以按如下方式执行:

msg[1] = (uint8_t)(bytesToRead >> 8);
msg[2] = (uint8_t)(bytesToRead);

持久性呢?您确定不需要可移植代码吗?请考虑使用位移。@如果我错了,伦丁纠正我,但我真的在乎苔藓吗?我只想把它作为uint16\u t发送,然后再作为uint16\u t值接收。值在内部如何存储重要吗?发送方计算机将具有endianess,实际协议将具有endianess,接收方将具有endianess。如果这三种枪中有一种使用不同的枪法,你就得小心了。@Lundin好的,我明白了。我是西方最快的枪!(我们发布了几乎相同的答案:)@Lundin-Well。我第一部分赢了,你是联盟的:)+1…我现在也是DV。哈哈…?很高兴你提到了
struct
padding。GCC确实允许使用某些编译器特定的语法消除它(不确定这在只能寻址对齐内存位置的CPU上如何工作),但这显然将您与GCC联系在一起。您能否详细说明这种“无效写入”条件的性质?@amn请参阅以获取更多详细信息。