2012-10-10 37 views
4

可能重複:
Undefined Behavior and Sequence Points會「p = p +(* p)++ * 3 + c;」導致未定義的行爲?

如在標準中定義,E1 + E2 =幾乎相同於E1 = E1 + E2除了E1只計算一次。所以,另外,會「p + =(* p)++ + c」;導致未定義的行爲?

在gcc/g ++(4.7/4.4)中嘗試下面的代碼。有2種結果:bxxxxx(g ++ 4.7)或axbxxx(gcc,g ++ 4.4)。如果我們在代碼中執行(1)而不是(2),我們只能得到axbxxx。

#include <stdio.h> 

int main() { 
    char s[] = "axxxxx"; 
    char *p = s; 

    printf("s = %s in the beginning.\n" 
      "p is pointed at the %d-th char.\n", s, p - s); 
    //p = p + (*p)++ * 3 + 2 - 'a' * 3; // (1) 
    p += (*p)++ * 3 + 2 - 'a' * 3; // (2) 
    printf("p is moved ahead by %d steps\n", p - s); 
    printf("s = %s after the operation.\n", s); 
    return 0; 
} 

我找不到爲什麼它會導致未定義的行爲,我也不能斷言它是一個gcc的錯誤。

對於axbxxx結果,我也不明白爲什麼操作數或後++被評估兩次(一旦獲取值,並稍後保存它)。由於在標準中說「1 ...被添加到它」,我認爲地址應該只被評估一次。如果post ++的操作數的地址只被求值一次,表達式的效果將是相同的,儘管以任何順序執行分配。

=== UPDATE ===

讀取第一個註釋鏈接的文檔後,我想下面的規則可能無關緊要:

「2)此外,前值應只訪問確定要存儲的值。「 。因此,「p = p +(* p)++ * 3 + c」中p的訪問是否被認爲是* p的「先值」的一部分,與要求的值無關存儲在* p?

IMO,這條規則沒有違反。

+1

檢查[this](http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points)。 – detunized

+0

感謝您的好文件。 –

+0

G ++的行爲更改爲4.7 by http://gcc.gnu.org/viewcvs?view=revision&revision=176072 –

回答

3

不,p = p + (*p)++ * 3 + c不會導致任何未定義的行爲,假設p不指向c

在這種情況下,可疑部分是在表達式中讀取和修改*p的值。但是,爲了確定新值p(新值p*p中讀取的值有直接的數據依賴性),讀取該值是爲了避免違反要求。

我猜想編譯器中的錯誤實際上源於其在未指定的情況下的錯誤行爲。請注意,表達式有兩個副作用:將新值存儲在p中,並將新值存儲在*p中。沒有指明這些副作用發生的順序。但是,在(*p)++子表達式的評估期間,編譯器應該「修復」++的特定左值參數,以確保新(增加的)值存儲在該確切對象中。看起來像舊版本的編譯器未能做到這一點,即首先評估p的新值,然後通過新的p存儲新值*p。這顯然是不正確的。

0

p += (*p)++ * 3 + 2 - 'a' * 3形式E1 = E1 + E2的。

  • 在右側有一個指針(地址變量)
  • 在左邊,你增加這個指針所指向的變量。

編輯:斑點p+=

還沒未定義,因爲無論上的E1 = E1 + E2右側的每個表達式的求值的順序,的p的值不變。

+0

OP海報是指「E1 + = E2」的定義,它由標準定義爲等同於'E1 = E1 + E2'。 – AnT

+0

謝謝我錯過了這個區別 – UmNyobe

1

原則上,該語句p += (*p)++ + c;可能是正確的。它所做的只是通過某個值提前指針(p),該值恰好由p指向的變量確定。

你只需要確保你永遠不會增加p超過s + 7。我沒有完全查看代碼保護­以查看是否屬於這種情況(但請注意,您正在使某些編碼連續性假設爲假)。

1

請注意,p += x;不等於p = p + x;,而是等於p = p + (x);。首先對x進行評估,並將結果添加到頁面。在標題中給出的沒有圓括號的公式中,p的中間值可能指向數組的外部,這實際上是未定義的行爲。只要x的結果在數組內,代碼中的版本應該沒問題。

6.5.16.2.3形式E1 OP = E2中的化合物,分配從僅在於 左值E1簡單賦值表達式E1 = E1 OP(E2)不同之處在於只計算一次。

J.2未定義行爲 - 加法或減法的指針成,或 剛好超出,陣列對象和一個整數型產生的結果 不指向成,或者剛好超出,相同的數組對象 (6.5.6)。

此UB定義不限於最終分配結果。