欧美一区二区三区,国内熟女精品熟女A片视频小说,日本av网,小鲜肉男男GAY做受XXX网站

a的值應該加一還是不變

錢艷冰2年前20瀏覽0評論

a的值應該加一還是不變?

結論:不同的編譯器,會得出不同的結果。

因為a = a ++這種表達式,在C語言規(guī)范中是屬于未定義的行為(Undefined behavior)。

以下面這段代碼為例,在Linux上打印0x1234,在Windows上打印0x1235。

下面分別在Windows和Linux上演示,并從匯編的角度,詳細講解一下。

Windows(Visual Studio 2015)

在Windows上,用VS2015編譯并運行,結果如下:

看一下反匯編:

藍色方框內(nèi)指令 mov dword ptr[a], 1234h 給變量a賦初值,也就是0x1234。

紅色方框內(nèi)兩條指令,看起來挺有意思:

第一條:mov eax, dword ptr[a] 把變量a的值加載到寄存器eax中。

第二條:mov dword ptr[a], eax 又把寄存器eax的值,存放到變量a中。

這兩條指令時沒有任何意義的。

綠色方框內(nèi)的三條指令:

第一條:mov ecx, dword ptr[a] 把變量a的值加載到寄存器ecx中,也就是0x1234。

第二條:add ecx, 1 把ecx的值加1,此時ecx = 0x1234 + 1 = 0x1235。

第三條:mov dword ptr[a], ecx 把寄存器ecx的值存放到變量a中,此時a的值是0x1235,這也是a最終的值。

不難看出,VS2015上,表達式 “a = a ++”被翻譯成下面的偽代碼表示:

a = 0x1234;

eax = a;

a = eax;

ecx = a;

ecx = ecx + 1;

a = ecx;

所以,最終變量a的值是0x1235。

Linux(GCC 8.3.0)

同樣的程序,在Ubuntu上用GCC 8.3.0編譯,并運行,結果為0x1234。如下圖:

把GCC編譯生成的目標文件進行反匯編,如下圖:

圖中,關鍵指令已經(jīng)標記出來了,應該比較容易理解了。不難看出,表達式“a = a ++”被GCC翻譯成如下偽代碼:

a = 0x1234;

eax = a;

edx = eax + 1;

a = edx;

a = eax;

因此,最終變量a的值是0x1234。

sequence point

C語言中有個重要的概念 - “sequence point”,有的翻譯為順序點或序列點,還有翻譯為執(zhí)行點的。C語言規(guī)范要求,編譯器必須保證,在某個sequence point上,它之前的所有表達式的計算都已經(jīng)確定,而它之后的所有表達式計算都尚未開始。

C語言規(guī)范中,對各種表達式定義了一系列的sequence point,感興趣的童鞋可以翻閱C語言規(guī)范。

對于“a = a ++;”這個表達式,C語言規(guī)范定義的sequence point是最后的分號“;”。但是,這個表達式中,可能改變a的值的地方卻有兩個:一個是對等號左邊的a賦值的操作,一個是等號右邊的a的自加操作。

這兩個操作之間,并沒有明確定義的sequence point。因此,才導致了不同的編譯器采用不同的計算順序,得出不同的結果。

其實,如果編譯時開啟告警選項,編譯時是會有告警信息的,比如GCC和Clang:

建議

C語言規(guī)范中,列舉了很多不確定的行為,主要有:

Unspecified behaviorUndefined behaviorImplementation-defined behaviorLocale-specific behavior

總之,有很多語法規(guī)則,C語言規(guī)范并沒有定義一個確定的輸出結果,不同的編譯器、版本、運行時環(huán)境、OS等都可能會產(chǎn)生不同的結果。

程序開發(fā)時,應該盡量避免使用這種容易產(chǎn)生歧義的語法規(guī)則。否則,很可能會在不同的環(huán)境上得到不同的結果,而且調試起來也相當費時!

對本文有疑問歡迎留言討論!覺得有用請點個贊!

對編譯器、OS內(nèi)核、虛擬化、性能調優(yōu)等技術感興趣的童鞋,歡迎關注!