999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

不同編譯器下自增自減表達式輸出不同值的研究

2023-12-25 03:25:04陳賢敏湯海晨陳治帆
電腦知識與技術 2023年31期

陳賢敏 湯海晨 陳治帆

摘要:同一個C語言的自增、自減表達式為什么在不同集成系統開發環境中產生不一樣的結果。使用GCC和Clang兩種不同的編譯器來驗證此實例表達式的值,并把兩種編譯好的C語言程序反編譯成匯編語言,再來分析代碼,目的是讓大家真正從底層了解為什么相同的表達式值會產生不同的結果。

關鍵詞:自增自減;GCC;Clang

中圖分類號:TP311? ? ? 文獻標識碼:A

文章編號:1009-3044(2023)31-0059-02

開放科學(資源服務)標識碼(OSID)

0 引言

C語言中的自增自減運算符(++和--)簡潔、緊湊、靈活。學生在做練習中遇到由自增自減運算符組成的復雜算術表達式,如p=(i++) +(i++) +(i++) 時,在不同的編譯器中可能會得到不同的運行結果[1],會讓用戶產生茫然疑惑。

國內對于C語言中的++、--用例有許多針對性的探討和研究,朱恩亮[2]在《Visual C ++與Turbo C處理自增自減運算表達式的區別》一文中列舉了在Visual C ++、Turbo C編程語言環境中,通過操作符的連接,可以構造出具有不同復雜程度的表達式。分析了i=3,表達式s1=(++y)+(++y)+(++y)值分別是s1=5+5+6=16和s1=6+6+6=18,產生不同結果是由于在C語言中操作符存在著優先級與結合性,并構造表達式后,不同語言系統的編譯會產生不同的結果。

夏超群[3]在《淺析C語言自增自減運算符的使用》一文,其例2的語中p=(i++) +(i++) (i++) 從理論上分析該語句中表達式(i++) +(i++) +(i++) 的值應為5+6+7,實際卻是VC++6.0環境下運算結果都是5+5+5。文中說明后置自增自減運算符的“先用后變”的“變”是指在下一條語句執行前統一改變,而不是剛用完就變。故該語句等價于:p=i+i+i;i=i+1;i=i+1;i=i+1。造成這種結果是因為高級語言的一條語句經編譯解釋成若干條機器指令,這若干條機器指令的順序最終決定該等價高級語言語句的執行結果。

為什么編譯系統會產生這兩種結果,以上作者的文中并未從源頭給出答案。因此本文通過把C程序代碼編譯后轉換成匯編語言并分析代碼的執行順序,真正從底層了解不同的編譯器為什么會產生不同的結果。

1 C語言實例

#include <stdio.h>

int main() {

int accumulate,i=5;

accumulate=(++y)+(++y)+(++y);

printf("accumulate=%d,i=%d",accumulate,y);

return 0;

}

大家看到此實例中的表達式accumulate=(++y)+(++y)+(++y),第一反應給出的答案為6+7+8,結果值為21,y的值為8,那是否正確呢?其實還可以給出第二種答案accumulate的值為22,y的值為8。

此實例C語言中的表達式accumulate=(++y)+(++y)+(++y)的背后運算到底是怎樣的一個過程,為什么此實例程序中的變量y等于5,最終程序運行會產生兩種不同的結果,分別是22和21。下面通過GCC編譯器模式和Clang編譯器模式驗證此實例在不同的編譯器得出的結果值是不一樣的。

1.1 實驗1

實驗環境操作系統是CentOS Linux,GCC編譯器模式,值為accumulate=22,y=8。通過GCC反編譯實例后如圖1,為了便于理解,圖2根據圖1一一對應寫成C語言格式,使讀者更好地理解匯編語句。

可以看出,表達式accumulate=(++y)+(++y)+(++y),語句(1) 先把[rbp-4]當成i變量,理解成把5賦給[rbp-4]變量,add DWORD PTR [rbp-4],1;語句(2) 相當于表達式中的第一項(++y) ,加1執行后[rbp-4]變量值6,i變量自然也是6了,執行語句(3) 匯編語句,相當于表達式中的第二項(++y) ,在原來[rbp-4]的基礎上又加1,得[rbp-4]值為7,自然i的值為7。語句(4) 簡單點說,就是把7賦給eax。難道繼續加1是i的值被替換成8嗎?顯然不是,語句(5) lea edx,[rax+rax] ,理解為edx=7+7=14此時才明白為什么在C語言中前兩項 (++y)+(++y)相加,也就是accumulate=7+7+(++y)。到這里讀者有點不理解了,這個rax為什么等于7。簡單解釋一下,32位和64位寄存器不是分開的寄存器,它們是重疊的:64位的rax,具有eax作為其底部的32位。因此,對32位寄存器的修改會反映在相應的64位寄存器中,反之亦然。繼續看語句(6) 中[rbp-4]是多少呢,它在執行語句(3) 后值沒有改變過,依舊是7,因此執行(6) add DWORD PTR [rbp-4],1。相當于表達式中的第三項(++y) ,[rbp-4]值為8,語句(7) [rbp-4]賦給了eax,eax值為8。繼續執行語句(8) add eax,edx ,可以把該語句轉換成熟悉的語句eax=eax+edx,已知文中語句(5) 已得出edx=14,因此可得出eax=eax+edx=8+14=22,如圖3所示。

1.2 實驗2

分析完了GCC編譯器模式,現以值為accumulate=21,y=8,按照同樣的方式分解一下由Clang編譯器模式編譯的程序,就會發現情況有所不同。

通過圖4、圖5可以看出,表達式accumulate=(++y)+(++y)+(++y),先通過語句(1) 、(2) ,把5賦給eax,語句(3) 累加1后把值賦給eax寄存器,eax值為6,相當于表達式第一項(++y)的值,注意先把第一項值6保留在eax寄存器,通過語句(4) 、(5) 把eax值為6賦給ecx,執行語句(6) ecx累加1后,值為7,相當于表達式第二項(++y),把第二項值也是獨立保存在ecx寄存器中。語句(8) eax=eax+ecx,得eax=6+7=13,從語句(9) 、(10) 可得出表達式第三項(++y)值為ecx=7+1=8,語句(12) 的結果為eax=eax+ecx=13+8=21,如圖6所示。

2 實驗結果分析

現在才明白實驗1中編譯器前兩項自增后,GCC編譯是前兩次y,(++y)+(++y)+(++y),原因是首先掃描求解前半部分,即(++y)+(++y)的值,先對y變量進行兩次自增運算,y的值變為7,再計算y+y的值為7+7=14,然后再求解后半部分,即14+(++y)的值,先對變量y自增1次,y的值變為8,再計算14+8=22,因此最終accumulate的值為22,y的值為8。

實驗2中,用Clang編譯器,再反編譯為匯編語言。通過匯編語言可以看出,前兩項y的值都分別獨立賦給不同的寄存器eax和ecx,因此前兩項(++y) 中的y就不會累加后再賦給相同的寄存器。而實驗1中(2) 、(3) 中兩條語句是對y進行累加后賦給,由原來的初值5變化7后,再賦給寄存器eax。

文中的實例accumulate=(++y)+(++y)+(++y)只是來證明這樣的式子在不同的編譯系統中會產生不同的值,因此在實際的工作生產和教學中不建議這樣來使用。任何類似(y++)+(y++)、(++j)+(++j)這樣的表達式,都屬于未定義行為。可以這么說,在C語言標準中沒有規定這樣的表達式應該如何計算,完全由編譯器自行決定,說到底編譯器也是由程序員來開發出來,當然不同的人有不同的邏輯理解,這樣也就導致不同的集成開發環境編譯器下自增和自減處理邏輯的不同。也進一步說明,由于自增自減表達式結果的不確定性,也就不具有可移植性,是十分不友好的表達式。

通過以上實例驗證,相同的表達式運行結果得出的值不一樣是由不同集成開發環境中的不同編譯器編譯造成的。實驗1、實驗2論證了使用GCC、Clang兩種不同的編譯器對同一段C語言源代碼進行編譯,得到了不同的值,它們按照各自思路轉化為了匯編代碼,通過對匯編語言的分析,最終找到了相同源代碼在不同的集成開發環境下結果是不一致的,這也是寫本篇論文的目的和任務。也通過上述實驗發現Clang的編譯器更能符合正常人的思維邏輯,在今后的學習工作中更推薦使用Clang編譯器的開發環境。

3 結束語

C語言中自增運算符為“++”,其作用是使變量的值增1;自減運算符為“--”,其作用是使變量的值減1[4]。當初制定這兩個C語言運算符是為了方便程序使用,但在使用y++、--y不恰當時會造成混淆,給剛入門學習C語言的人員帶來混亂。

當然,像文中的實例代碼移植性差,需要大家盡量避免,分析這樣的運算順序也沒有任何意義。建議大家盡量不要去研究這樣的表達式,也更不要在實際編程中寫出這樣的表達式。所以,在編寫程序時,有選擇地小心謹慎使用自增(自減)運算符來簡化程序,在一些容易出錯的地方可以用其他方法代替,從而保證程序的執行萬無一失[5]。當然在實際項目中,考慮到項目遷移等問題,建議不要使用連續自增、自減進行運算,這種邏輯問題在項目維護過程中很難被發現和維護。

參考文獻:

[1] 袁玲.在DEV C++環境下C語言自加自減運算符使用分析[J].電腦知識與技術,2016,12(27):248-249.

[2] 朱恩亮.Visual C+ +與Turbo C處理自增自減運算表達式的區別[J].鹽城工學院學報(自然科學版),2003,16(3):27-28,31.

[3] 夏超群.淺析C語言自增自減運算符的使用[J].武漢工程職業技術學院學報,2010,22(3):47-49.

[4] 周亮.淺談C語言中自增自減運算符的應用[J].電腦知識與技術,2010,6(17):4714-4715.

[5] 唐婷,呂浩音.C語言自增(自減)運算符運算規律的探討[J].隴東學院學報,2016,27(5):8-11.

【通聯編輯:謝媛媛】

主站蜘蛛池模板: 久久久无码人妻精品无码| 人妻少妇久久久久久97人妻| 日韩a级毛片| 在线观看亚洲精品福利片| 免费a在线观看播放| 欧美无遮挡国产欧美另类| 精品无码国产自产野外拍在线| 欧美一级专区免费大片| 精品无码一区二区三区电影| 欧美天天干| 日本精品一在线观看视频| 中文字幕久久亚洲一区| 伊人网址在线| 国产一在线| 国产成人狂喷潮在线观看2345 | 国产高清在线观看91精品| 国产黑丝视频在线观看| 亚洲三级片在线看| 欧美另类视频一区二区三区| 国模在线视频一区二区三区| 99久久国产综合精品女同| 国产一二三区视频| 欧洲免费精品视频在线| 久久精品国产在热久久2019 | 日本尹人综合香蕉在线观看| 成人精品亚洲| 狠狠色噜噜狠狠狠狠奇米777| 久久精品视频一| 国产玖玖玖精品视频| 日韩少妇激情一区二区| 69国产精品视频免费| 国产青青草视频| 狠狠亚洲婷婷综合色香| 少妇被粗大的猛烈进出免费视频| 国产乱人激情H在线观看| 欧亚日韩Av| 大学生久久香蕉国产线观看| 中文字幕资源站| 亚洲最新地址| 精品久久综合1区2区3区激情| 日韩欧美国产三级| 国产手机在线ΑⅤ片无码观看| 国产女人在线| 国产精品久久久久久久久久98| 久久综合色天堂av| 9966国产精品视频| 国产免费a级片| 污污网站在线观看| 99无码中文字幕视频| 五月激情综合网| 天堂久久久久久中文字幕| 全部无卡免费的毛片在线看| 91黄色在线观看| 国产噜噜噜视频在线观看| 日韩欧美在线观看| 成人亚洲视频| 国产成人超碰无码| 国产精品嫩草影院av| 欧美午夜小视频| 91亚洲免费| 97精品伊人久久大香线蕉| 午夜激情福利视频| 在线五月婷婷| 国产精品毛片一区| 欧美成人午夜视频免看| 高清无码手机在线观看| 99久久无色码中文字幕| 亚洲日韩第九十九页| 久久大香伊蕉在人线观看热2| 亚洲91在线精品| 成人av手机在线观看| 爆乳熟妇一区二区三区| 亚洲欧美色中文字幕| 欧美日韩v| 亚洲国产成熟视频在线多多| 亚洲国产精品人久久电影| 日本在线欧美在线| 激情综合五月网| 国内精品九九久久久精品| 国产主播在线观看| 国产成人凹凸视频在线| a欧美在线|