2015-02-09 53 views
0

好吧,我明白GCC 4.x警告「解引用類型打斷的指針會打破嚴格別名規則」不是玩笑,我應該清理我的代碼。類型雙引號(GCC) - 在堆棧上增加一個指針參數

我使用GCC 3.x編譯和運行的代碼,如果使用GCC 4.x也會很高興。假設我想讓彙編的代碼儘可能短:函數傳遞一個指針,並且應該向其中寫入一些數據。我原來的代碼直接在堆棧上使用指針(沒有副本),並在那裏增加它(請注意,我不想將增加後的值傳遞給調用者)。你也可以考慮通過寄存器傳遞參數 - 然後任何副本都會被開銷。

所以這是我的「理想」的代碼:

void foo(void *pdataout) { 
    for (int i=16; i--;) 
     *(*reinterpret_cast<BYTE**>(&pdataout))++ = 255; 
} 

我嘗試了一些變種(注意地址,運營商必須在任何類型的鑄造之前應用於「pdataout」):

void foo(void *pdataout) { 
    BYTE *pdo = reinterpret_cast<BYTE*>(*reinterpret_cast<BYTE**>(&pdataout)); 

    for (int i=16; i--;) 
     *pdo++ = 255; 
} 

而且這樣的:

void foo(void *pdataout) { 
    BYTE *pdo = *reinterpret_cast<BYTE**>(&pdataout); 

    for (int i=16; i--;) 
     *pdo++ = 255; 
} 

沒有取悅GCC 4.x的......這最後一個做 - 但是,它使用參數的副本W¯¯我不喜歡。有沒有辦法做到這一點沒有副本?我不知道如何告訴它的編譯器:-(

void foo(void *pdataout) { 
    BYTE *pdo = reinterpret_cast<BYTE*>(pdataout); 

    for (int i=16; i--;) 
     *pdo++ = 255; 
} 
+0

我真的不明白爲什麼複製指針(並只增加副本)可以解決任何問題 - 或者代碼仍然危險,但GCC不會檢測到它?首先與上一段代碼片段進行比較。如果有人能解釋我會很高興! – tueftl 2015-02-10 15:06:38

+0

看來問題可以簡化爲'float test = 0.0f;如果(!*(long *)&test){}; long * ptest =(long *)&test; if(!* ptest){};':第一個'&test'行會產生警告,其他行不會。爲什麼?最後2行是否安全? – tueftl 2015-02-10 15:44:38

回答

0

據我現在明白,儘管有一個由GCC沒有更多的警告,通過一個額外的變量是不是安全使用間接!

對我來說(因爲union不可用),唯一真正的解決方案是使用-fno-strict-aliasing編譯器選項。只有這樣,GCC纔會知道指向同一個內存地址的不同類型的指針可以引用同一個變量。

This article終於幫我理解過程rstand嚴格別名。