亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        C 語言程序的理解與編譯優(yōu)化

        2020-08-07 14:44:38吳元斌
        現(xiàn)代計算機(jī) 2020年18期
        關(guān)鍵詞:程序語言

        吳元斌

        (重慶三峽學(xué)院計算機(jī)科學(xué)與工程學(xué)院,重慶404000)

        0 引言

        在多年的C 語言教學(xué)實踐中發(fā)現(xiàn),不少初學(xué)者對C 語言中運算求值存在一些模糊認(rèn)識。很多人認(rèn)為C語言的算術(shù)表達(dá)式求值順序與數(shù)學(xué)中算術(shù)表達(dá)式的求值順序相同,即先乘除、后加減。C 語言標(biāo)準(zhǔn)規(guī)定了運算符間的優(yōu)先級及同級運算的結(jié)合性[1],也是乘除運算的優(yōu)先級高于加減運算,因此對于表達(dá)式a+b-c*d,其運算順序看起來是:*、+、-,但事實上并非如此。

        一些習(xí)題包括一個變量多次自增(或自減)求和的表達(dá)式,如:(a++)+(a++)。C 語言并沒有規(guī)定這兩個自增運算與相加的求值順序。通常的理解是:先求左邊自增的值,再求另右邊自增的值,最后將兩個值相加,但實際上,有些編譯器進(jìn)行了優(yōu)化:先進(jìn)行兩次自增,然后再將兩個a 相加。還有其它依賴于編譯器的問題,出現(xiàn)在習(xí)題或思考題甚至考試題中。這種情況是應(yīng)該避免的,因此程序的運行結(jié)果是依賴于編譯器的,在不同的編譯器下運行結(jié)果可能不同。

        為了清楚的理解C 語言教學(xué)中存在的一些編譯相關(guān)的問題,使初學(xué)者編寫與不依賴于編譯器的C 語言程序,本文將列舉一些典型的C 語言示例程序,給出了它們在集成開發(fā)環(huán)境Eclipse + MinGW GCC、LCCWin32 以及在Visual Studio 2019 下的運行結(jié)果對比。由于多數(shù)示例程序的運行結(jié)果存在一些差異,進(jìn)一步展示、對照和分析了源程序在開源編譯器MinGW GCC和LCC 下目標(biāo)程序的反匯編程序,目標(biāo)程序的反匯編程序是利用Eclipse+MinGW GCC、LCC-Win32 兩種集成開發(fā)環(huán)境調(diào)試程序環(huán)境下得到的。本文還對編譯器翻譯算術(shù)表達(dá)式的基本思想進(jìn)行說明,并分析編譯器在表達(dá)式運算求值順序?qū)崿F(xiàn)中的具體差異。

        1 示例源程序及其目標(biāo)程序反匯編分析

        1.1 算術(shù)表達(dá)式中運算的次序

        算術(shù)表達(dá)式是用二元運算符+、-、*、/和圓括號連接起來的滿足語法和語義規(guī)則的式子,C 語言規(guī)定了其中運算符的優(yōu)先級和結(jié)合性,如圓括號的優(yōu)先級最高,之后是乘除,加減最低,同一優(yōu)先級的兩個算術(shù)運算符的結(jié)合性是從左到右,但C 語言算術(shù)表達(dá)式中運算的次序不等同于數(shù)學(xué)中運算的次序。通過分析一些C 語言教材[2-4]中給出的容易引起模糊認(rèn)識的示例,用下列典型程序段進(jìn)行說明:

        照數(shù)學(xué)運算規(guī)則,賦值語句右邊的表達(dá)式運算順序依次是:*、/、*、+、-,運算過程和結(jié)果可以表示為:a* 4 + b/ 2- c * b →12 + b/ 2- c * b →12 + 2 - c *b →12+2-20 →14-20 →-6。雖然C 語言程序中表達(dá)式的運行結(jié)果值也是-6,但運算次序與上述數(shù)學(xué)運算次序是不同的。編譯程序是用下面的文法對算術(shù)表達(dá)式進(jìn)行了嚴(yán)格的定義,文法指明了運算符的結(jié)合性和優(yōu)先級,算術(shù)表達(dá)式的文法為[5-6]:

        其中非終結(jié)符E 表示一組以+號或-號分隔的項所組成的表達(dá)式;T 表示由一組以*號或/號分隔的因子所組成的項,F(xiàn) 表示因子,它是用括號括起來的表達(dá)式或標(biāo)識符id。變量和常數(shù)被詞法分析程序歸類為標(biāo)識符id。利用該文法生成上面表達(dá)式的語法樹是唯一的,如圖1 所示。

        圖1 生成示例表達(dá)式的語法樹

        其中,圖中的id 對應(yīng)的變量或常量從左到右依次是a、4、b、2、c、b。通過語法制導(dǎo)翻譯(類似于語法樹自下而上或遞歸下降分析),上述表達(dá)式被翻譯成為每條指令最多一個運算符的指令序列[5]。將上述表達(dá)式計算的同一示例程序在兩種集成環(huán)境中調(diào)試視圖截圖(源程序及反匯編)如圖2 所示,左圖是Eclipse+Min-GW GCC,右圖LCC-Win32,兩個子圖的上面部分都是源程序,下面都是目標(biāo)程序的反匯編程序。左、右兩圖放在一起是便于對比分析(下面示例都采用這種方式)。

        其中左圖中最后用紅色邊框包括的列為手工添加的代碼說明,右圖的反匯編用圓括號包含了變量名。兩種編譯器采用的指令不完全相同,左圖中除法比右圖的實現(xiàn)復(fù)雜,詳細(xì)分析可見文獻(xiàn)[7]。可以看出,兩個編譯器處理表達(dá)式的運算次序相同的,它們的次序都是:*、/、+、*、-,顯然與數(shù)學(xué)運算規(guī)則不同。這個運算次序也就是圖1 中的語法樹按運算符從下到上、從左到右得到的運算次序。

        實際上,C 語言算術(shù)表達(dá)式求值中在處理當(dāng)前運算符時,要與其右邊相鄰的運算符進(jìn)行比較,若當(dāng)前運算符高于其相鄰右邊的運算符,或者它們的優(yōu)先級相同,且結(jié)合性是從左到右,則完成當(dāng)前運算,否則先處理其右邊相鄰的運算,其右邊相鄰的運算也要處理方法也是相同的,如此等等,直到所有運算完成。編譯器自下而上的翻譯法在表達(dá)式最后添加了一個運算符$(優(yōu)先級最低)運算符[5-6],它就沒有右邊相鄰的運算符了。

        圖2 兩種編譯器表達(dá)式運算次序相同

        1.2 表達(dá)式運算次序的副作用

        很多時候無論是按數(shù)學(xué)運算次序還是按編譯程序指定的次序運算,算術(shù)表達(dá)式的值是相同的,看起來不用區(qū)分C 語言表達(dá)式的運算次序,但并不總是這樣。當(dāng)表達(dá)式中存在項與項之間的值存在依賴關(guān)系時,結(jié)果就可能不同,如將上面的程序段修改為:

        所作的修改只是將上例的表達(dá)式最后一項改為(b=2),由于第2 項中的b 與最后一項的b 存在依賴關(guān)系,編譯器MinGW GCC 與LCC 對表達(dá)式的優(yōu)化處理不同,程序在兩種環(huán)境下的運行結(jié)果不同,分別為4和3,在Visual Studio 2019 下運行的結(jié)果也為3。

        該程序在MinGW GCC 與LCC 編譯反匯編對比如圖3 所示,分析發(fā)現(xiàn)LCC 編譯器中b 賦值為2 的指令被提前,MinGW GCC 則沒有,兩條指令分別用紅色方框標(biāo)出,表達(dá)式中其它的運算次序還是與上例相同??梢?,兩種編譯器只是對“(b=2)”的處理不同,在LCC環(huán)境下表達(dá)式中所有b 的值都是2,而在MinGW GCC環(huán)境下只是最后的b 的值為2,因此導(dǎo)致了程序的運行結(jié)果不同,所以該程序的運行結(jié)果完全依賴于編譯環(huán)境。

        圖3 兩種編譯器對運算次序優(yōu)化存在差異

        1.3 函數(shù)實參的求值順序處理

        C 語言也沒有指定函數(shù)各參數(shù)的求值順序[1]。在函數(shù)調(diào)用時,有的編譯器是從左到右,有的則是從右到左。參考文獻(xiàn)[3]有一個類似于下面的程序段:

        通過在MinGW GCC 與LCC 下運行程序后發(fā)現(xiàn),第1 個輸出語句的運行結(jié)果不同,分別為“3 3”和“3 0”,而第1 個輸出語句在Visual Studio 2019 下運行的結(jié)果為“3 3”。三種環(huán)境下第2 個輸出語句的結(jié)果為“3 3 3”,即變量a、b、c 的值最后都是3,這說明在三種環(huán)境下編譯器的求值順序都是從右到左。由于第1 個輸出存在差異,為了找出問題的原因,將該程序在Min-GW GCC 與LCC 編譯反匯編進(jìn)行對比,如圖4 所示。

        圖4 兩種編譯器對實參求值的處理不同

        分析圖4 發(fā)現(xiàn),兩種編譯器都是先計算右邊的參數(shù)(左圖中第1 個加框的部分為第1 個參數(shù)的求值,右圖中為第1 個加框指令的前6 條指令),然后計算左邊的參數(shù)。但是它們處理值的方式不同,對MinGW GCC環(huán)境中,printf 輸出的是變量a 的最終值(左圖第2 個加框部分)。但在LCC 環(huán)境中是將兩個實參的值分別保存在寄存器rbx、rdi 中,計算一個保存一個(右圖中兩個加框指令),rbx 的值為0,rdi 的值為3。可見盡管都是從右到左計算函數(shù)實參,但形參的值卻不同,程序的執(zhí)行結(jié)果也依賴于編譯程序,只有仔細(xì)分析它們的反匯編程序,才能搞清楚其中的原因。

        1.4 自增自減運算的副作用

        函數(shù)調(diào)用、嵌套賦值語句、自增與自減運算符都有可能產(chǎn)生“副作用”—在對表達(dá)式求值的同時,修改了某些變量的值[1]。一些C 語言教材的練習(xí)中常常包含類似于下面的程序段:

        上述程序在MinGW GCC 和LCC 下下的運行結(jié)果分別為“11 14 7 7”和“11 13 7 7”,在Visual Studio 2019下的運行結(jié)果為“11 14 7 7”??梢娸敵鼋Y(jié)果存在差異,為了找出問題的原因,將該程序在MinGW GCC 與LCC編譯反匯編進(jìn)行對比,如圖5 所示。

        圖5 兩種編譯器對自增運算處理不同

        在圖5 中,分別對兩種環(huán)境下相關(guān)指令功能進(jìn)行了說明(紅色框線中)??梢钥闯觯瑑煞N環(huán)境下對后綴的自增運算處理相同,即先累加,再自增,再累加,再自增,累加的結(jié)果都是11。但對于前綴的自增運算處理則不同,在MinGW GCC 下前綴的自增運算被優(yōu)化(在加法運算前進(jìn)行),而在LCC 下前綴的自增運算則不同,并沒有優(yōu)化,所以前綴的自增運算相加的結(jié)果不同,分別為14 和13。因此一個變量多次自增(或自減)求和表達(dá)式的值也依賴于編譯器。

        2 結(jié)語

        本文討論了C 語言教學(xué)中一些容易引起初學(xué)者產(chǎn)生模糊認(rèn)識的典型問題,通過不同編譯環(huán)境對目標(biāo)程序的反匯編對照與分析,能夠清楚地看到這些程序的運行結(jié)果依賴于編譯器,不同編譯器可能產(chǎn)生不同的結(jié)果。這樣的問題還很多,雖然初學(xué)者也不一定能夠理解這些分析及編譯原理的具體細(xì)節(jié),但教學(xué)中應(yīng)該讓他們知道編寫依賴于編譯器的程序是不好的習(xí)慣。在任何一種編程語言中,如果代碼的執(zhí)行結(jié)果與求值順序有關(guān),則都是不好的程序設(shè)計風(fēng)格。很自然,有必要了解哪些問題需要避免,但是,如果不知道這些問題在各種機(jī)器上是如何解決的,就最好不要嘗試運用某種特殊的實現(xiàn)方式[1]。因此,C 語言教學(xué)一個很重要的工作是讓學(xué)生學(xué)會正確的編程方法,培養(yǎng)良好的編程習(xí)慣[2],避免編寫執(zhí)行結(jié)果依賴于編譯器的C 語言程序。

        猜你喜歡
        程序語言
        語言是刀
        文苑(2020年4期)2020-05-30 12:35:30
        試論我國未決羈押程序的立法完善
        讓語言描寫搖曳多姿
        失能的信仰——走向衰亡的民事訴訟程序
        “程序猿”的生活什么樣
        多向度交往對語言磨蝕的補正之道
        英國與歐盟正式啟動“離婚”程序程序
        累積動態(tài)分析下的同聲傳譯語言壓縮
        創(chuàng)衛(wèi)暗訪程序有待改進(jìn)
        我有我語言
        日日天干夜夜狠狠爱| 亚洲av产在线精品亚洲第三站| 亚洲国产成人va在线观看天堂| 日本高清色惰www在线视频| 91精品国产高清久久久久| 亚洲精品一品二品av| 91青青草视频在线播放| 久久影院最新国产精品| 日韩中文字幕一区二区二区| 久久婷婷五月综合色奶水99啪| 97se亚洲国产综合自在线观看 | 亚洲av色香蕉一区二区三区蜜桃 | 加勒比东京热久久综合| 中文字幕精品人妻丝袜| 中文字幕一区久久精品| 精品国产三级a∨在线欧美| 国产精品久久久久9999吃药| av潮喷大喷水系列无码| 国产色诱视频在线观看| 91福利国产在线观看一区二区| 久久久久国产亚洲AV麻豆 | 色综合天天综合网国产成人网| 日韩人妻无码一区二区三区久久| 成人久久久久久久久久久| 八戒网站免费观看视频| 人妻无码一区二区在线影院| 亚洲av中文无码乱人伦在线咪咕 | 亚洲精品国产第一区三区 | 优优人体大尺大尺无毒不卡| 少妇激情一区二区三区视频| 国产suv精品一区二人妻| 亚洲国产高清在线一区二区三区 | 久久婷婷五月综合色奶水99啪| 亚洲欧美在线观看| 免费成人毛片| 精品国产爱在线观看| 国产黑丝美女办公室激情啪啪| 国产欧美日韩va另类在线播放| 国产精品欧美福利久久| 毛片免费全部无码播放| 最新国产成人在线网站|