2012-01-11 47 views
15

我試圖在編譯使用GCC的特定程序時修復兩個警告。該警告是:解除引用類型指針的指針將打破嚴格別名

警告:提領型punned指針將打破 嚴格走樣規則[-Wstrict走樣]

和兩個罪魁禍首是:

unsigned int received_size = ntohl (*((unsigned int*)dcc->incoming_buf)); 

*((unsigned int*)dcc->outgoing_buf) = htonl (dcc->file_confirm_offset); 

incoming_buf and outgoing_buf定義如下:

char     incoming_buf[LIBIRC_DCC_BUFFER_SIZE]; 

char     outgoing_buf[LIBIRC_DCC_BUFFER_SIZE]; 

這似乎比警告我一直在研究的其他例子稍有不同。我寧願修復問題,而不是禁用嚴格別名檢查。

已經有很多建議使用聯合 - 對於這種情況可能是合適的聯合?

+1

有趣...嚴格別名不應該適用於'char *'。或者我錯過了什麼? – Mysticial 2012-01-11 18:30:14

+3

@Mysticial是的,你所錯過的是,當'T1'類型的對象用'T2'類型的左值和'T2'爲'char'訪問時,沒有別名違規,但當'T1'是'char '和'T2'不是'char'的有符號/無符號變體,則存在混疊違規。 – ouah 2012-01-11 19:08:49

+0

@ouah你應該做出答案。 – Mysticial 2012-01-11 19:11:19

回答

26

首先,我們來看看爲什麼會出現鋸齒違規警告。

別名規則簡單地說,你只能通過自身的類型,它的符號/無符號變量類型訪問對象,或通過字符類型(charsigned charunsigned char)。 C表示違反鋸齒規則調用未定義的行爲(所以不要!)。

在這一行你的程序:

unsigned int received_size = ntohl (*((unsigned int*)dcc->incoming_buf)); 

雖然incoming_buf數組的元素是char類型的,你正在訪問他們作爲unsigned int。實際上,表達式*((unsigned int*)dcc->incoming_buf)中的解引用運算符的結果是unsigned int類型。

這違反了別名規則,因爲您只有權訪問incoming_buf數組元素(參見上面的規則摘要!)charsigned charunsigned char

通知你有完全相同的別名問題在你的第二個罪魁禍首:

*((unsigned int*)dcc->outgoing_buf) = htonl (dcc->file_confirm_offset); 

您可以通過訪問unsigned intoutgoing_bufchar元素,所以它是一個別名衝突。

提出的解決方案

要解決你的問題,你可以嘗試有您要訪問您的陣列的類型直接定義的元素:

unsigned int incoming_buf[LIBIRC_DCC_BUFFER_SIZE/sizeof (unsigned int)]; 
unsigned int outgoing_buf[LIBIRC_DCC_BUFFER_SIZE/sizeof (unsigned int)]; 

(通過寬度的方式unsigned int是實現定義的,因此如果程序假設unsigned int是32位,則應考慮使用uint32_t)。

這種方式,您可以存儲陣列中unsigned int對象,而不通過類型char訪問的元素,像這樣違反別名規則:

*((char *) outgoing_buf) = expr_of_type_char; 

char_lvalue = *((char *) incoming_buf); 

編輯:

我完全重寫了我的答案,特別是我解釋了程序爲什麼會從編譯器獲取別名警告。

+0

這似乎工作。我對你所建議的數組做了修改,並在其他地方將其他引用修改爲incoming_buf。現在警告是固定的。非常感謝。 – BlankFrank 2012-01-11 22:22:26

+0

@BlankFrank不客氣! – ouah 2012-01-11 22:24:13

11

要解決這個問題,不要雙關和別名!唯一的「正確」的方式來讀取類型T是分配一個類型T,如果需要填充其表示:

uint32_t n; 
memcpy(&n, dcc->incoming_buf, 4); 

簡而言之:如果你想要一個整數,你需要做一個整數。沒有辦法以一種語言寬容的方式對此進行欺騙。你被允許(對於I/O的目的,通常)

唯一指針轉換是治療的現有變量T類型的的地址作爲char*,或者更確切地說,作爲指針的第一個元素字符數組的大小爲sizeof(T)

-2

將指針指向無符號,然後返回指針。 (*)(unsigned *)((unsigned)dcc-> incoming_buf)));}}};

2
union 
{ 
    const unsigned int * int_val_p; 
    const char* buf; 
} xyz; 

xyz.buf = dcc->incoming_buf; 
unsigned int received_size = ntohl(*(xyz.int_val_p)); 

簡單的解釋 1. C++,你應該嘗試自己對齊數據標準規定,G ++去的加倍努力,以產生關於這個問題的警告。 2.如果您完全理解架構/系統和代碼中的數據對齊方式,您應該只嘗試一下(例如上面的代碼在Intel 32/64上是確定的;對齊方式1; Win/Linux/Bsd/Mac ) 3.使用上述代碼的唯一實際原因是爲了避免編譯器警告,WHEN和IF你知道你在做什麼

相關問題