程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 序列點在C語言表達式求值中的作用

序列點在C語言表達式求值中的作用

編輯:關於C語言

序列點在C語言表達式求值中的作用


摘要:

本文開創性地分析了序列點在C語言表達式求值中的作用:序列點左邊的操作數要先於其右邊的操作數求值。討論了逗號操作符,、邏輯與操作符&&、邏輯或操作符||和條件操作符?:的問號處需要序列點的原因。舉例分析了序列點在表達式求值中的作用。

關鍵字:序列點 表達式求值 C語言

C語言作為一種主流程序設計語言,許多編程語言如Java、C++、C#都借鑒了它的語法。C語言也是一種很適當的程序設計入門的教學語言,國內大專院校的許多專業都開設了這門課程並且大多將其作為第一門程序設計語言課程,同時C語言也是全國計算機等級考試二級的內容。因此,C語言的教學質量對學生的後續學習和取得等級證書很重要,尤其是對學生在實際工作中更好地了解和使用計算機有非常重要的意義。

目前,國內絕大多數教材在介紹C語言表達式時,都沒有介紹C語言的一個重要概念——序列點[1]。序列點概念的缺失使得讀者只能記憶而不是遵循求值規則分析有序列點表達式的求值順序。以簡單的逗號表達式a = 3, ++a為例,設變量a為整型變量(下面表達式中出現的變量也默認為整型)。“逗號表達式自左向右依次求值”,故先對子表達式a = 3求值,再對子表達式++a求值。在實際教學中善於質疑的學生往往會問:表達式中自增操作符++的優先級最高,為何要先求子表達式a=3的值?表達式求值時不是先算高優先級的操作符嗎?表達式究竟有沒有求值原則呢?這不僅使得學生對C語言知識的認知殘缺不全,而且也影響了學生自主學習的積極性,不利於創新型人才的培養。

一、序列點的定義及分析

根據C語言標准[2],序列點就是執行序列中的一些特定點,在這些點上,前面求值的副效應(side effect)應徹底完成且其後求值的副效應均未發生。在教材中照搬標准讓初學者學習理解序列點是不明智的,應直接向初學者指出序列點在表達式求值中起的作用。含有序列點的表達式求值時要保證有序列點的操作符左邊的由子表達式構成的操作數先於其右邊的操作數求值[3]。C語言表達式求值的原則為:先考慮序列點,再根據操作符的優先級和結合性求值。

操作數是指操作符的操作對象,如表達式3+2中加法操作符左邊的操作數為3,右邊的操作數為2。在復雜的表達式中,需結合操作符的優先級和結合性來確定某操作符的操作數。對於表達式3+2*5,加法操作符左邊的操作數為3,但其右邊的操作數不為2,進行加法運算時3顯然不可能和2相加。因為與加法操作符右邊相鄰的操作符為乘法操作符,其優先級較高,所以加法操作符右邊的操作數為2*5(的積)。而乘法操作符左邊的操作數為2,右邊的操作數為5。對於表達式3+2-5,加法操作符右邊相鄰的操作符為減法操作符,兩者優先級相同,但結合性為左結合,故它右邊的操作數為2。

表達式a = 0 && ++a中邏輯與左邊的操作數為0,右邊的操作數為子表達式++a,整個表達式為賦值表達式;而表達式(a = 0) && ++a中邏輯與左邊的操作數為子表達式(a = 0),右邊的操作數為子表達式++a,整個表達式為邏輯表達式。邏輯與操作符有序列點,因此表達式(a = 0) && ++a求值時,雖然自增操作符的優先級最高,但求值時首先考慮序列點,邏輯與操作符左邊的操作數(a = 0)需先於其右邊的操作數++a求值。

二、C語言中部分操作符需要序列點的原因

逗號操作符(,)有序列點。逗號操作符多用於把多條語句變成一條語句,如a = 2;和++a;為兩條語句,而a = 2, ++a;是一條語句。語句a = 2, ++a;執行時,如果逗號操作符沒有序列點,子表達式++a就會先執行,即這條語句的執行順序與上面兩條語句的並不相同。基於逗號操作符的作用,逗號操作符只能優先級最低,且含有序列點。

邏輯與操作符(&&)有序列點。C語言中邏輯與操作符實行“短路計算”,即當其左邊的操作數值為0即假時,不對右邊的操作數求值而直接把0(假)作為求值的最終結果。如果邏輯與操作符沒有序列點,表達式3>5 && ++a求值時,自增操作符的優先級最高,子表達式++a應先求值。邏輯與操作符左邊的操作數3>5求值的結果為0,即假,根據短路計算,作為邏輯與右邊的操作數,子表達式++a不會被求值。顯然兩者矛盾。為了短路計算,邏輯與操作符&&需要序列點。有了序列點之後,求值時序列點左邊的操作數將先於其右邊的操作數求值,即子表達式3>5先求值,由於短路計算,整個表達式的值為0,即假,且右操作數子表達式++a不會被求值。

邏輯或操作符(||)有序列點。C語言中邏輯或操作符也實行“短路計算”,因此,其有序列點的必要性與邏輯與操作符的相同。

條件操作符?:的問號處?有序列點。條件操作符常用於改寫簡單的if-else選擇結構,如下面的語句

if(a > b)

++a;

else

++b;

可用條件操作符改寫為a > b ? ++a : ++b;。

如果條件操作符沒有序列點,語句a > b ? ++a : ++b;執行時,++a和++b會先於子表達式a > b執行,這樣的執行順序顯然與if-else選擇結構的不同,因此,條件操作符?:的問號?處有序列點。語句a > b ? ++a : ++b;執行時,問號處?左邊的操作數a > b先執行,值為真時,對++a求值,不對++b求值;值為假時,反之。

三、含有序列點的表達式的求值分析

設整型變量a的值為0。對於表達式'a' || (a = 1) && (a += 2),邏輯或||左邊的操作數為'a',右邊的操作數為(a = 1) && (a += 2);邏輯與&&左邊的操作數為(a = 1),右邊的操作數為(a += 2)。求值時首先考慮序列點,邏輯或左邊的操作數'a'的值非“0”為真,執行短路計算,其右邊的操作數不會被求值,因此,整個表達式的值為1,即真。在表達式求值的過程中,變量a的值沒有改變。

對於表達式(a = 0) && (a = 5) || (a += 1),邏輯與&&左邊的操作數為(a = 0),右邊的操作數為(a = 5);邏輯或||左邊的操作數為(a = 0) && (a = 5),右邊的操作數為 (a += 1)。求值時首先考慮序列點,邏輯與&&左邊的操作數(a = 0)先求值,求值時一方面變量a的值會變成0,另一方面這個子表達式的值為0即假,執行短路計算,其右邊的操作數(a = 5)不會被求值,因此,原表達式變為0 || (a += 1)。邏輯或||左邊的操作數值為0,即假,不能短路計算,只能再求其右邊操作數的值。子表達式(a += 1)求值時一方面變量a的值由0變成1,另一方面這個子表達式的值為1即真,因此,原表達式的值為1,即真。表達式的求值完成後,變量a的值變為1。

特別強調,用賦值表達式作為邏輯操作符的操作數僅僅為了清晰地表明在表達式求值過程中某個子表達式是否被求值,這類表達式的實用性和可讀性非常差,實際編程時最好不要用賦值表達式做操作數。

序列點不僅可以使低優先級的操作符先於高優先級的操作符求值,而且也可以影響操作符的結合性。表達式a > b ? ++a : c > d ? ++c : ++d有兩個條件操作符,條件操作符為右結合,因此,原表達式的求值順序應為(a > b ? ++a : (c > d ? ++c : ++d))。左邊條件操作符的3個操作數分別為子表達式a > b,子表達式++a和子表達式c > d ? ++c : ++d。按照結合性,子表達式(c > d ? ++c : ++d)應先求值,但是,由於左邊條件操作符的問號處?有序列點,故子表達式a >b先求值,如果其為真,則只會對子表達式++a求值,而不會再對子表達式c > d ? ++c : ++d求值了。顯然,此表達式中條件操作符的右結合只用於確認左邊條件操作符的右操作數,而沒有使得右邊條件操作符先求值。

四、結束語

雖然C語言表達式種類繁多,但有著相對明確的表達式求值規則,根據求值規則正確分析出表達式的求值順序有助於激發學生學習的主動性。在教材中照搬C語言標准中序列點的概念勢必會增加學習的難度,給初學者提供一個准確且易於理解的概念,不僅不會造成C語言知識點的殘缺,而且也為啟發式教學提供了可能。

參考文獻

[1]黃瑛,胡烈,朱其慎. 序列點——C語言教學的一個普遍盲區[J].電腦知識與技術,2011(3):2105-2106.

[2]國家技術監督局. GB/T 15272-1994 程序設計語言C[S]. 北京:中國標准出版社,2004.

[3]周二強著. C語言內涵教程[M]. 中國鐵道出版社,2013:68.

Effect of Sequence Point on Expression Evaluation in Language C

Abstract:

The effect of the sequence point on expression evaluation in Language C is analyzed from all new angle of view. The operand in the form of sub-expression located to the left of the operator with sequence point is evaluated before the right operand. This text explains the reason the comma operator, logical AND operator, logical OR operator and ternary conditional operator need sequence points. The role of the sequence point on expression evaluation is discussed by citing examples.

Keywords: sequence point; expression evaluation; language C

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved