C語言中賦值表達式的返回值是什么?


我們或多或少都有過,或者見過將賦值表達式參與運算的情況。這通常會伴隨着一些意想不到的問題。今天我就見到了一段奇怪的代碼:

#include<stdio.h>
int main()
{
int a =5;
int b = (a=2)+(a=3);
printf("%d %d\n",a,b);
return 0;
}

乍一看,似乎答案很明朗,按照順序運算之后,a的值是3,b的值是5.有經驗的程序員肯定會一眼看出,這里的計算過程是一個未定義行為(Undefined behavior).在這里簡單來說就是:無法確定哪一個括號里的表達式會先執行。
括號只能改變運算符的結合律,不能改變表達式的求值順序。這個順序是取決於編譯器的。所以a的值是2還是3是不能確定的。
這段代碼在gcc(Ubuntu)下得到的結果是

3 6

而在clang(Mac)下運行的結果是

3 5

為什么會這樣呢? 這是怎么一回事呢?

查看它們生成的匯編代碼

gcc
...
  movl  $5, -8(%rbp) // a=5
  movl  $2, -8(%rbp) // a = 2
  movl  $3, -8(%rbp)  //a = 3
  movl  -8(%rbp), %eax  // eax = a
  addl  %eax, %eax //eax = eax + eax
  movl  %eax, -4(%rbp) // b = eax
...


clang
...
movl  $5, -8(%rbp)
movl  $2, -8(%rbp)  // a = 2
movl  $3, -8(%rbp)  // a = 3
movl  $5, -12(%rbp) // b = 5
...

在gcc的理解中

a = (b=c)
//會被改寫成
b=c
a=b
//所以對於
a = (b=c)+(d=e)
//會被改寫成
b = c
d = e
a = b+d
//當b和d為同一個值的時候,變量空間被復用了,

在clang的理解中

a = (b=c)+(d=e)
//被改寫成了
i=b=c
j=d=e
a=i+j
//所以直接得到了賦值符號右邊表達式值之和

由此得出結論:賦值表達式的返回值為賦值符號右邊的值。

但在某些特殊情況下,使用某些編譯器可能無法得到想要的結果。所以我們應當盡量避免使用賦值表達式的值參與運算。

注意:雖然在兩個例子中,a的值都是3,但這並不意味着表達式的求值順序是從左往右的。

有關編譯器求值順序的詳細內容可以參考這篇文章


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM