簡體   English   中英

C ++中對運算符優先級的混淆

[英]Confusion over operator precedence in C++

在以下測試表達式中說:

int ggg9 = fggg2() + (fggg3() && fggg4() < fggg5() * fggg6());
//                 4          11         6         3

如果我們遵循運算符優先級 (顯示在表達式下方的注釋行中),則我假設將首先對parens中的表達式進行求值,然后將結果添加到fggg2()

因此,我假設它將按以下順序解決:

int r1 = fggg5() * fggg6(); //Precedence 3 (inside parens)
int r2 = fggg4() < r1;      //Precedence 6 (inside parens)
int r3 = fggg3() && r2;     //Precedence 11 (inside parens)
int ggg9 = fggg2() + r3;    //Outside of parens, so it's last

但是x86-64 gcc 8.2 可以這樣解決

在此處輸入圖片說明

(我將其轉換回C ++)

    int i0;
    int r2 = fggg2();
    int r3 = fggg3();
    if(!r3) goto L13;
    int r4 = fggg4();
    int r5 = fggg5();
    int r6 = fggg6();
    int i1 = r5 * r6;
    if(r4 >= i1) goto L13
    i0 = 1;
    goto L14
L13:
    i0 = 0;
L14:
    int ggg9 = i0 + r2;

那么為什么當&&運算符的優先級分別為&&似乎先於* ,然后<呢?

最后,為什么通過首先評估fggg2()似乎並不關心parens? VS2017似乎最后評估了它。

從我看來, gcc編譯器只是從左到右評估了所有這些功能,而沒有考慮優先級。

您正在將優先級評估順序混淆。

這是一個非常常見的混亂。 可能是因為英語中的“ precede”一詞具有時間含義。 但這實際上是從等級層次的意義上講(例如here )。

在更簡單的表達式a() + b() * c()優先級告訴我們*運算符的操作數為b()c()+的操作數為a()且乘法。 一無所有,一無所有。

函數a,b,c可能仍可以任何順序調用。

的確, *值計算必須在+值計算之前執行,因為我們需要知道前者的結果才能計算后者。

值計算是評估操作數的不同步驟。 必須先計算運算符的操作數,然后再計算其值,但沒有比這更嚴格的要求了。 沒有關於評估操作數的部分排序的規則。

的左操作數+可能的右操作數之前評估+ ,即使正確的操作是由許多子表達式。 編譯器可能會評估所有“葉”操作數,將結果存儲在堆棧中,然后執行值計算。

未必存在值計算的一個嚴格的順序任一,例如以w() * x() + y() * z()這兩個值的計算*可以按任一順序進行。


在您的代碼中, &&運算符確實具有特殊的排序限制(有時稱為short )。 在開始評估右操作數之前,必須先評估左操作數。

優先級告訴我們&&的左操作數是fgg3()&&的右操作數是fggg4() < fggg5() * fggg6()) 因此,要求在fgg4fgg5fgg6任何一個之前調用fgg3() 在示例中,對操作數的求值順序沒有其他限制。 所述fgg2可以發生在任何時間, 456可以是任何順序,只要它們都是后3

您將運算符的優先級與求值順序混淆了,雖然可以保證保留優先級,但不求值順序,編譯器可以自由選擇該順序。

它可以首先在其他操作數的評估中間或之間評估fggg2()

您忘記了&&運算符的短路評估因素。

&&運算符的左側總是先於右側進行求值。

為了簡化操作,必須對r3的前半部分求值,如果它的結果​​為false,則不會調用r1r2任何一個。

C ++中需要進行短路評估。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM