簡體   English   中英

C語言中的運算符優先級

[英]Operator Precedence in C language

有人可以告訴我這里幕后發生的事情嗎?

main()
{
    int z, x=5, y=-10, a=4, b=2;
    z = ++x - --y*b/a;
    printf("%d", z);
}

奇怪的方式寫代碼的人...無論如何...我嘗試...

  1. 解析++x--y
  2. 解決乘法和除法
  3. 解決剩余的(正負)

所以...

  1. z= 6 - (-11) * 2 /4
  2. z= 6 - (-22) / 4
  3. z= 6 - (-5) (由於(-22) / 4是整數除法,結果被截斷了)

我得到z= 11

變量z被聲明為int,因此變為11

我建議以更簡單的方式寫這行! 哦,抱歉我的英語...

這個表達

z=++x - --y*b/a;

在抽象機中按以下順序求值

變量x遞增並等於6。變量y遞減並等於-11。 變量y乘以變量b ,結果等於-22。 前一個運算的結果除以變量a並且使用整數算術時,結果等於-5。

最后,從變量x減去結果,結果等於11。

運行程序,並確定我是否正確。

考慮到特定的實現可能以不同的順序評估操作數,條件是結果與我為抽象機描述的結果相同。

根據C標准(5.1.2.3程序執行)

4在抽象機中,所有表達式均按語義指定的方式求值。 如果實際實現可以推斷出未使用表達式的值並且沒有產生所需的副作用(包括由調用函數或訪問易失性對象引起的副作用),則無需對表達式的一部分進行求值。

首先,請注意運算符優先級子表達式求值順序之間的區別。

運算符優先級指示在將這些運算的結果與表達式的其余部分一起使用之前,必須執行和評估的運算。 這類似於數學優先級: 1 + 1 * 2保證給出結果3,而不是4。因為*具有比+高的優先級。

求值順序等於實際的執行順序,並且是未指定的行為 ,這意味着編譯器可以自由選擇以自己喜歡的順序執行各種子表達式,以便生成最快的代碼。 而且我們不知道順序。 C中的大多數運算符都涉及未指定的求值順序(某些特殊情況(如&& || ?: , )除外)。

例如,在x = y() + z() ,我們可以知道+操作將在=之前執行,但我們無法確定yz中的哪個函數將首先執行。 結果可能與結果無關緊要,具體取決於功能的作用。


然后到問題中的表達式:

  • 運算符優先級指示必須先評估兩個操作++x--y然后再執行其他運算,因為前綴一元運算符的優先級--y表達式中的運算符。
  • 沒有指定首先評估的++x--y*b/a子表達式。 我們不能說出執行順序(而--y*b/a確實包含幾個子表達式)。 無論如何,這里的評估順序無關緊要,不會影響結果。
  • 遞增/遞減++x--y將在將這些運算的結果與表達式的其余部分一起使用之前發生。
  • 然后,運算符優先級指示必須先評估涉及*/的運算。 這些運算符具有相同的優先級,但是它們屬於乘法運算符組,該運算符組具有從左到右的關聯性 ,這意味着--y*b/a可以保證首先評估--y*b 在此之后,結果會得到分成a
  • 因此,最右邊的整個子表達式等於( (--y) * b ) / a
  • 接下來,運算符優先級指示-優先級高於= 因此,子表達式++x的結果--y*b/a表達式--y*b/a減去。
  • 最后,將結果分配給z ,因為=具有最低的優先級。

編輯

順便說一句,編寫相同代碼並獲得完全相同的機器代碼的正確方法是:

++x;
--y;
z = x - (y*b)/a;

除了降低可讀性外,++和-運算符還可能與其他運算符混合使用,因此很危險,因為它們具有副作用 每個表達式具有多個副作用,很容易導致各種形式的無序處理,這始終是一個錯誤,可能很嚴重。 參見示例。

“運算符優先級”是指用於確定每個運算符的操作數的規則。 在您的情況下,請使用括號表示:

z=++x - --y*b/a;

等效於:

z = ((++x) - (((--y) * b) / a));

現在,此行代碼和以下printf語句具有與代碼相同的可觀察到的行為

z = (x + 1) - ((y - 1) * b / a);
printf("%d\n", z);
x = x + 1;
y = y - 1;

C是根據可觀察到的行為定義的(大致表示程序生成的輸出;您可以通過閱讀C標准來查看技術定義)。 根據該標准將產生相同可觀察行為的任何兩個程序都被視為完全等效。

有時稱為“假設規則”,正是該規則允許進行優化


解決其他一些答案提出的要點:圍繞++--有一些規則。 具體來說,定義了遞增x和遞減y的效果,以便在執行z=++x - --y*b/a;任何時候都可以寫回遞增和遞減的z=++x - --y*b/a; 它們可以是順序的,也可以是同時的。 減量的寫入可以在(y-1) * b的計算之前或之后,依此類推。

在一些不同的代碼示例中,我們將使用這些規則來確定程序的可觀察行為 ,並且它不像該特定程序那樣靈活。

但是在此代碼示例中,由於其他任何內容都不取決於這些增量和減量的時間,因此事實證明,根據“假設規則”,我們甚至可以將它們提升到printf之上。

暫無
暫無

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

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