2017-04-25 68 views
2

在功能解决GCC警告:“提领类型punned指针将打破严格走样规则”的临时指针

size_t csps_socket_read(csps_socket_t *s, csps_packet_wrapper_t *packet, size_t sz) 

我得到警告:“提领型punned指针将打破严格走样规则对下面的行[-Wstrict走样]“:

packet_size = ((csps_packet_full_header_t *)s->receive_mem)->size + header_size; 

如果我重写这样的:

csps_packet_full_header_t *packet_full_header = (csps_packet_full_header_t *)s->receive_mem; 
packet_size = packet_full_header->size + header_size; 

我没有收到警告。为什么?问题仍然存在,但gcc无法看到它?

这里的结构有关:

typedef struct csps_socket_t_ 
{ 
    void*  fp; 
    bool  open; 
    uint8_t  receive_mem[CSPS_SOCKET_MEM]; 
    uint32_t receive_index; 
} csps_socket_t; 

typedef struct ATTR_PACKED csps_packet_full_header_t_ 
{ 
    uint8_t version:4; 
    uint8_t pclass:4; 
    uint8_t ch:1; 
    uint8_t reserved:7; 
    uint16_t size; 
    uint16_t sequence; 
    uint16_t checksum; 
    uint8_t src[8]; 
    uint8_t dst[8]; 
} csps_packet_full_header_t; 
+3

是的,问题仍然存在,但是当您使用中间变量时,似乎GCC会失去踪迹。您的代码具有未定义的行为,并可能在各种情况下崩溃,或者可能不会;它也取决于位字段的布局是非常多的实现定义。此外,需要检查'receive_mem'的对齐方式 - 如果uint16_t成员未对齐,则可能导致崩溃 –

+0

我建议使用'memcpy',如下所示:http://stackoverflow.com/q/17789928您可以看到在任何优化级别下,编译器都能够将它理解为类型双击并省略实际的内存副本。 https://godbolt.org/g/r6VoO0 – ephemient

+0

@AnttiHaapala请注意OP在问GCC问题,而不是如何重写代码以避免UB。 – yugr

回答

2

基本上这是GCC的-Wstrict-aliasing机械的错误。众所周知,它们都会产生错误的警告并错过实际的别名违规(请参阅开发人员的this comment)。

问题出现在这两种情况下,铸造不相关的结构会违反别名规则,并可能导致GCC产生意外的代码。