C語言陷阱

最近一直做C編譯器相關(guān)的開發(fā),感覺該總結(jié)一下。以前一直以為對C已經(jīng)足夠熟悉了,結(jié)果被它奇葩的語法樹震驚了。碰巧最近心血來潮,想把一個GNU的僵尸項(xiàng)目jamvm救活改造一下,又發(fā)現(xiàn)了GCC的一些奇葩C語言擴(kuò)展。

聲明

C語言的聲明足夠奇怪,以至于丑魚書用了一章來解釋這個問題。對于一般的變量聲明,C語言采用的語法一般是T var的形式,T表示變量的類型,var表示變量的名字。但對于數(shù)組的聲明,如果要聲明一個大小為10的int數(shù)組a,C語言需要

int a[10]

而不是

int[10] a

而許多其他的語言采用的往往是類似后者的方式,比如Java,C#,Go等等。

函數(shù)的聲明同樣的問題。比如這樣的一個函數(shù)

int foo(int a, int b)
{
    return a + b;
}

它的類型可以表示為int ()(int, int), 其實(shí)一定有人發(fā)現(xiàn)了,如果對foo函數(shù)做前向引用的聲明,我們會這么寫:

int foo(int, int);

而不是

int ()(int, int) foo;

函數(shù)指針也是同樣的問題,對于foo函數(shù)的指針,類型可以表示為int (*)(int, int),但聲明函數(shù)指針時,我們只能

int (*f)(int, int)

即聲明了一個變量f,類型為指針類型,指向目標(biāo)的類型為int ()(int, int)。如果想用T var的形式聲明函數(shù)指針,只能曲線救國,利用typedef。

C語言之所以把聲明形式搞得這么復(fù)雜,原因或許是為了追求變量的定義和使用盡量寫法上保持一致。怎么樣,是不是很奇怪?除了引入復(fù)雜性,本身完全不一樣的兩個概念非要寫的一樣有何用?比如這個聲明是啥意思?

char* const (next)()

左值

先說結(jié)論。C99標(biāo)準(zhǔn)明確說明了Cast不能作為左值,所以現(xiàn)在的編譯器(gcc4.x或者clang3.x)遇到這種情況都會complain。但是老版本gcc居然有一個擴(kuò)展,名曰casts-as-lvalue。

左值可以簡單理解為允許被賦值的值,可以被放在賦值號(=)左邊的值。那什么樣的值可以放在賦值號左邊?權(quán)威的解答需要參考ISO/IEC 9899:1999。為了方便我用CIL對左值的定義舉例

lval =
     | Mem of exp
     | Var of varinfo</pre>

可以看到左值如果是一個表達(dá)式,那么一定只一個訪存操作。比如*(ptr+1) = 1,顯然這里的ptr是一個指針類型。在編譯jamvm1.0版本源碼的時候,出現(xiàn)了大量的lvalue required as left operand of assignment錯誤。這里錯誤大部分都長的這個樣*((long long*)ptr)++ = 1。我根據(jù)代碼上下文理解,它是想根據(jù)強(qiáng)制類型轉(zhuǎn)換后的類型進(jìn)行指針自增操作。不過經(jīng)過我調(diào)研,發(fā)現(xiàn)現(xiàn)在的編譯器已經(jīng)不支持一行代碼實(shí)現(xiàn)類似這樣語義的操作了。如果想要編譯含有這樣語句的C代碼,可以嘗試使用gcc3.3.6。gcc3.3.6支持cast-as-lvalue擴(kuò)展,但是本身并不含有cast-as-lvalue的代碼。

undefined behaviour

只舉個例子。比如*p++ = p[-1],賦值號兩邊的計算順序不同編譯器是不同的,C標(biāo)準(zhǔn)對它沒有做嚴(yán)格的要求。所以這種寫法在開發(fā)中一定要避免,clang默認(rèn)會拋一個warning,gcc不加-Wall參數(shù)不會有任何提示。

總結(jié)

  1. 不要為了少寫一兩行代碼而是用一些非標(biāo)準(zhǔn)的extenstion或者trick,得不償失。
  2. Treat all warning as error !

對JVM感興趣的話,jamvm1.0的確是個不錯的起點(diǎn),不到7000行的C,實(shí)現(xiàn)了一個java虛擬機(jī)該有的幾乎所有功能。問題是現(xiàn)在的主流編譯器都無法編譯它了。neojam是對jamvm1.0代碼修改后可以用gcc4.x編譯的版本,鏈接先放在這,相關(guān)文檔補(bǔ)全后會public。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容