天天看點

GNU C 手冊 第五章

作者:黃三章

5 文法詞彙

為了開始全面描述C語言,我們解釋了C代碼的文法詞彙和詞彙單元。程式設計語言的詞彙單元稱為标記。本章涵蓋了C的所有标記,但常量除外,這将在後面的章節中介紹。一種重要的标記是辨別符,它用于任何類型的名稱。

5.1 用英語編寫程式!

原則上,您可以用任何人類語言編寫程式中的函數名和變量名,以及注釋。C允許在注釋中使用任何類型的字元,您可以将非ASCII字元放入帶有特殊字首的辨別符中。然而,為了使所有國家的程式員都能了解和開發該程式,在當今的情況下,最好用英語編寫辨別符和注釋。

英語是所有國家的程式員普遍學習的語言。如果一個程式的名稱是英文的,孟加拉國、比利時、玻利維亞、巴西和保加利亞的大多數程式員都能了解。這些國家的大多數程式員都會說英語,或者至少能閱讀,但他們根本不會對方的語言。在印度,語言如此之多,兩個程式員可能除了英語之外沒有共同語言。

如果你對用英語寫作沒有信心,那麼盡力吧。

5.2 字元

GNU C源檔案通常以ASCII字元集編寫,該字元集在20世紀60年代為英語定義。但是,它們也可以包括以UTF-8多位元組編碼表示的Unicode字元。

在C源代碼中,非ASCII字元在注釋、寬字元常量和字元串常量中都是有效的。

在常量(字元或字元串)和辨別符中指定非ASCII字元的另一種方法是使用以反斜杠開始的轉義序列指定期望的Unicode字元。

對于某些字元,C接受稱為二合字母的雙字元别名。

5.3 空白

空白是指存在于檔案中但在檔案的列印清單中顯示為空白的字元(或久遠年代前,傳統上顯示為空白的字元)。C語言需要空白來分隔兩個連續的辨別符,或者将辨別符與數值常量分隔開。除此之外,在後面描述的一些特殊情況下,空格是可選的;您可以在需要時将其放入,以使代碼更易于閱讀。

C代碼中的空格和制表符被視為空白字元。換行也是如此。您可以使用newline(也稱為linefeed 或 LF)、CR(回車符)或CRLF序列(兩個字元:回車符後跟換行符)表示換行。

formfeed字元,即Control-L,傳統上用于将檔案分頁。在源代碼中它仍然以這種方式使用,并且用于生成源代碼的漂亮列印件的工具仍然在每個“formfeed”字元之後開始一個新頁。将代碼分成由formfeed字元分隔的代碼頁是一種很好的方法,可以将代碼分解為可了解的片段,并向其他程式員表明它們的起點和終點。

傳統上,垂直制表符Control-K用于使列印前進到頁面的下一部分。我們不知道在源代碼中使用它的具體原因,但它在C中仍然被接受為空白。

注釋在文法上也等同于空白。

5.4 注釋

注釋是存在于源代碼中對代碼的邏輯沒有影響的文本。

注釋的目的是向閱讀代碼的人解釋代碼。為您的代碼編寫好的注釋非常重要。它們應該提供背景資訊,幫助程式員了解代碼以這種方式編寫的原因。六個月後傳回代碼時,您将需要這些注釋的幫助,以記住您為什麼以這種方式寫代碼。

過時的注釋變得不正确會适得其反,是以軟體開發人員的部分責任是根據需要更新注釋,以适應程式代碼的更改。

C允許兩種注釋文法,傳統樣式和C++樣式。傳統的C注釋以“/”開頭,以“/”結尾。例如,

/* This is a comment in traditional C syntax. */

傳統注釋可以包含“/”,但這些定界符不成對嵌套。第一個出現的“/”結束注釋,不管它是否包含“/*”序列。

/* This /* is a comment */ But this is not! */

行注釋以“//”開頭,以行結尾。例如,

// This is a comment in C++ style.

行注釋确實存在嵌套,隻不過,行注釋内的“//”實際上是它的一部分,如下,

// this whole line is // one comment This is code, not comment.

将行注釋放在塊注釋中是安全的,反之亦然。

/* traditional comment
   // contains line comment
   more traditional comment
 */ text here is not a comment

// line comment /* contains traditional comment */
           

但是要小心用行注釋注釋掉傳統注釋的一端。如果定界符“/*”出現在另一個注釋的内部,它不會啟動新的注釋。

// line comment  /* That would ordinarily begin a block comment.
    Oops! The line comment has ended;
    this isn't a comment any more.  */
           

字元串常量中無法識别注釋。 “/blah/”是字元串常量,不是空字元串。

在本手冊中,為了可讀性,我們以可變寬度字型顯示注釋中的文本,但源檔案中不存在這種字型差別。

注釋在文法上等同于空白,是以它總是分隔标記。是以

int/* comment */foo;
is equivalent to
  int foo;
           

但是幹淨的代碼總是使用真正的空白來将注釋與周圍的代碼在視覺上分隔開。

5.5 辨別符

C中的辨別符(名稱)是字母和數字,以及“_”的序列,但不能以數字開頭。大多數編譯器也允許“$” 。辨別符可以是任意長度;例如

int anti_dis_establishment_arian_ism;           

辨別符中的字母區分大小寫;是以,a和a是兩個不同的辨別符。

C中的辨別符用作變量名、函數名、類型定義名、枚舉常量、類型标記、字段名和标簽。C中的某些辨別符是關鍵字,這意味着它們具有特定的文法含義。C中的關鍵字是保留詞,這意味着不能以任何其他方式使用它們。例如,不能定義名為return或if的變量或函數。

您還可以在辨別符中包含其他字元,甚至非ASCII字元,方法是在辨別符名稱中寫入以“\u”或“\u”開頭的Unicode字元名。然而,在辨別符中使用非ASCII字元通常是一個壞主意,當它們用英語書寫時,它們永遠不需要非ASCII字元。

空白用來分隔兩個連續辨別符,或将辨別符與前一個或後一個數字常量分隔。

5.6 運算符和标點符号

在這裡,我們描述了C語言中運算符和标點符号的詞彙文法。具體的運算符及其含義将在後續章節中介紹。

C中的大多數運算符由一個或兩個字元組成,這些字元不能用于辨別符。C中用于運算符的字元是“!~ ^&|*/%+-=<>,.?:” 。

有些運算符是兩個字元。例如, “++”是增量運算符。多字元運算符的識别是通過将盡可能多的連續字元組合在一起構成一個運算符來實作的。

例如,字元序列“++”總是被解釋為增量運算符;是以,如果我們想寫入運算符“+”的兩個連續執行個體,我們必須用空格分隔它們,以便它們不會合并為一個标記。應用相同的規則,a+++++b總是标記為a++ ++ +b,而不是a++ + ++b,即使後者可以是有效C程式的一部分,而前者不能(因為a++不是左值,是以不能是++的操作數)。

一些C運算符是關鍵字而不是特殊字元。它們包括sizeof和_Alignof 。

字元“;{}[]()”用于标點和分組。分号( “ ;” )結束一條語句。大括号(“{”和“}”)在語句級開始和結束一個塊,或者用于包圍一個變量(如數組或結構)的初始值清單。

方括号(“[”和“])用于數組索引,如數組[5]。

括号用于表達式中表達式的顯式嵌套、圍繞函數聲明或定義中的參數聲明以及函數調用中的參數清單,如printf(“Foo%d\n”,i)。有幾種語句也使用括号作為其文法的一部分,例如if語句、for語句、while語句和switch語句。

括号還被用于圍繞運算符關鍵字sizeof和_Alignof的操作數,當操作數是資料類型而不是值時。

5.7 續行

反斜杠和換行的序列在C程式中的任何位置都被完全忽略。這使得可以在源檔案中将單個源行拆分為多行。GNUC容忍并忽略反斜杠和換行之間的其他空白。特别是,如果某些文本編輯器決定以CRLF序列結束行,它總是忽略其中的CR(回車)字元。

在C語言中,行連續的主要用途是用于一行過長的宏定義中。

可以使用反斜杠換行符在另一行上繼續行注釋。您可以将反斜杠換行放在辨別符、甚至關鍵字或運算符的中間。您甚至可以使用反斜杠換行符将“/”、“/”和“//”拆分為多行。下面是一個醜怪的例子:

/\
*
*/ fo\
o +\
= 1\
0;
           

這相當于“/**/foo+=10;”。

在實際的程式中不要做這些事情,因為它們使代碼難以閱讀。

注意:因為要在源代碼中使用某些工具的緣故,明智的做法是在每個源檔案末尾使用一個前面沒有反斜杠的換行符,這樣它就真正結束了最後一行。