C語言陷阱

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

聲明

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), 其實一定有人發(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,類型為指針類型禁荸,指向目標的類型為int ()(int, int)右蒲。如果想用T var的形式聲明函數(shù)指針,只能曲線救國赶熟,利用typedef瑰妄。

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

char* const (next)()

左值

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

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

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

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

undefined behaviour

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

總結

  1. 不要為了少寫一兩行代碼而是用一些非標準的extenstion或者trick,得不償失闺魏。
  2. Treat all warning as error 未状!

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

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搔课,一起剝皮案震驚了整個濱河市糯累,隨后出現(xiàn)的幾起案子漩仙,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件魁巩,死亡現(xiàn)場離奇詭異,居然都是意外死亡姐浮,警方通過查閱死者的電腦和手機谷遂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卖鲤,“玉大人肾扰,你說我怎么就攤上這事〉坝猓” “怎么了集晚?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長区匣。 經(jīng)常有香客問我偷拔,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任莲绰,我火速辦了婚禮欺旧,結果婚禮上,老公的妹妹穿的比我還像新娘蛤签。我一直安慰自己辞友,他們只是感情好,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布震肮。 她就那樣靜靜地躺著称龙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪戳晌。 梳的紋絲不亂的頭發(fā)上茵瀑,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音躬厌,去河邊找鬼马昨。 笑死,一個胖子當著我的面吹牛扛施,可吹牛的內(nèi)容都是我干的鸿捧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼疙渣,長吁一口氣:“原來是場噩夢啊……” “哼匙奴!你這毒婦竟也來了?” 一聲冷哼從身側響起妄荔,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤泼菌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后啦租,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哗伯,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年篷角,在試婚紗的時候發(fā)現(xiàn)自己被綠了焊刹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡恳蹲,死狀恐怖虐块,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嘉蕾,我是刑警寧澤贺奠,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站错忱,受9級特大地震影響儡率,放射性物質(zhì)發(fā)生泄漏颁糟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一喉悴、第九天 我趴在偏房一處隱蔽的房頂上張望棱貌。 院中可真熱鬧,春花似錦箕肃、人聲如沸婚脱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽障贸。三九已至,卻和暖如春吟宦,著一層夾襖步出監(jiān)牢的瞬間篮洁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工殃姓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留袁波,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓蜗侈,卻偏偏與公主長得像篷牌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子踏幻,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容