2008-11-04 22 views
23

我一直在試圖理解嚴格的別名規則,因爲它們適用於字符指針。對於嚴格的指針別名,char *安全嗎?

Here這是說:

它總是假定一個char *可以指任何對象的別名。

好了,所以在插座代碼的情況下,我可以這樣做:

struct SocketMsg 
{ 
    int a; 
    int b; 
}; 

int main(int argc, char** argv) 
{ 
    // Some code... 
    SocketMsg msgToSend; 
    msgToSend.a = 0; 
    msgToSend.b = 1; 
    send(socket, (char*)(&msgToSend), sizeof(msgToSend); 
}; 

但後來有這種說法

反過來是不正確的。將char *轉換爲除char *以外的任何類型的指針並將其解除引用通常違反了嚴格的別名規則。

這是否意味着,當我的recv字符數組,我不能重新解釋投一個struct當我知道消息的結構:

struct SocketMsgToRecv 
{ 
    int a; 
    int b; 
}; 

int main() 
{ 
    SocketMsgToRecv* pointerToMsg; 
    char msgBuff[100]; 
    ... 
    recv(socket, msgBuff, 100); 
    // Ommiting make sure we have a complete message from the stream 
    // but lets assume msgBuff[0] has a complete msg, and lets interpret the msg 

    // SAFE!?!?!? 
    pointerToMsg = &msgBuff[0]; 

    printf("Got Msg: a: %i, b: %i", pointerToMsg->a, pointerToMsg->b); 
} 

將第二個例子不是因爲工作基類型是一個char數組,我將它轉換爲一個結構?你如何在嚴格的別名世界中處理這種情況?

+0

第二段代碼是否要求你明確陳述?你是否啓用了所有警告? – 2017-11-13 02:40:37

回答

6

正確,第二個示例違反了嚴格的別名規則,所以如果使用-fstrict-aliasing標誌進行編譯,則可能會得到不正確的目標代碼。完全正確的解決辦法是在這裏使用一個聯盟:

union 
{ 
    SocketMsgToRecv msg; 
    char msgBuff[100]; 
}; 

recv(socket, msgBuff, 100); 

printf("Got Msg: a: %i, b: %i", msg.a, msg.b); 
+1

這是否符合標準或只是編譯器讓你脫離寫入一個成員和從另一個成員讀取? – 2010-05-06 00:26:21

+9

工會是完全沒有必要的。只需將一個指針傳遞給結構(轉換爲`char *`)爲`recv`。 – 2010-09-03 01:38:31

7

重新@Adam羅森菲爾德:工會將達成共識,只要字符*的供應商開始了在做類似的事情。

退後一步並弄清楚這是怎麼回事可能是有用的。

別名規則的基礎是這樣一個事實:編譯器可能會將不同簡單類型的值放在不同的內存邊界上以改善訪問,並且硬件在某些情況下可能需要這種對齊才能夠使用指針。這也可以在存在各種不同大小的元素的結構中顯示出來。該結構可能會在良好的邊界上啓動。另外,編譯器仍然可以在結構體內部引入鬆散咬合來實現需要它的結構元素的正確對齊。

考慮到編譯器經常有選項來控制所有這些處理或不處理的方式,您可以看到有很多方法可以發生意外。當傳遞指向結構體的指針(將其轉換爲char *或不作爲char)傳遞到編譯爲期望不同對齊約定的庫中時,這一點尤爲重要。

char *?

有關char *的推定是sizeof(char)== 1(相對於所有其他大小的數據的大小),並且該char *指針沒有任何對齊要求。因此,一個真正的char *總是可以安全地傳遞併成功使用,而不用擔心對齊問題,這適用於char []數組的任何元素,在指針上執行++和 - 等等。 (奇怪的是,void *並不完全相同。)

現在你應該能夠看到,如果你將某種結構數據轉移到一個本身沒有對齊的char []數組中,試圖轉回到一個需要對齊的指針可以一個嚴重的問題。

如果進行一個char []數組和一個結構,要求最苛刻的對準的並集(即,該結構的)將被由編譯器兌現。如果供應商和消費者正在有效地使用匹配的聯合,以便將struct *轉換爲char *並返回正常工作,這將工作。

在這種情況下,我希望的數據以類似於聯合產生的指針之前把它澆鑄爲char *或將其轉移任何其他方式的的sizeof(char)的字節的陣列。確保所依賴的庫和您自己的代碼之間的編譯器選項兼容也很重要。

相關問題