2017-04-25 26 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產生意外的代碼。

相關問題