C語言的黑暗角落: implement-defined,unspecified,undefined

來源:互聯網
上載者:User
原文出處:http://blog.chinaunix.net/space.php?uid=53564&do=blog&id=2099623

讀ANSI C標準, 或K&R, 或C: A reference manual時, 往往會碰到對某個語言特性這樣的描述. 這三者到底是什麼意思, 我的粗略印象, 從implement-defined, 到unspecified, 到undefined, 依次越來越不靠譜, 越發危險, 越發不可移植. 僅有這樣的模糊認識是不夠的, 實際上, 求證於典籍之後, 還是不十分清朗.


關於為什麼會有這3個晦澀的短語, 來迷惑我這樣的平民百姓, 難道是所謂語言律師們給我下的套?
Rationale中說:


我的理解是:
未指定的行為, 未定義行為, 和實現定義的行為用于歸類那些本標準沒有, 或是不能完全描述其屬性的程式的結果. 對其分類的目的是為了允許不同的編譯器實現可以有一定程度的靈活性. 這樣也鼓勵編譯器實現品質成為市場競爭的主導因素. 同時也能在允許編譯器在實現一些受歡迎的語言擴充的同時, 還能打著遵循語言標準的金字招牌. 標準中告知性的附錄J把語言中的這些行為分門別類地歸納到上述三種行為.未指定的行為給具體實現者留下了一定的自由度. 這種自由不能越過編譯器失敗的極限(包括編譯器失敗, 下面對"未定義行為"的討論更證實了這一點), 因為無論如何, 只要任何實現不引起未定義行為, 所有可能的行為都算是"正確的".未定義行為等於給實現者發了免死金牌, 實現者可以放任程式中存在錯誤, 只因為這些錯誤太難應對. 同時未定義行為也為可能的語言擴充開啟了一扇門: 實現者可以通過對標準中官方聲稱的未定義的行為作出定義來增強語言.
C99標準中說:

3.4.1  實現定義的這個是三者之中最好理解的, 它有幾個特點:1. 具體的編譯器自己做決定. 2. 但不能是拒絕編譯, 也就是說不能編譯失敗.3. 編譯器必需在文檔中說明它選擇的行為.4. 標準本身並不提供可選的方案(與 unspecified 相比)
3.4.3 未定義的行為
基本上, 未定義最能讓具體編譯器天馬行空, 為所欲為. 包括編譯失敗. 這可能是最省事的做法.舉例說不可移植的特性, 或錯誤的程式結構(gcc的__attribute__((***)), 或是在運算式中允許塊結構, 算不算是), 或是錯誤的資料(這個想不出例子). 對出現這些情況, 而本標準又對具體實現未作要求的. 算作未定義行為.
舉例是整型溢出.
3.4.4 未指定的行為
標準中給定了2種或更多的選擇, 除此之外標準沒有額外地要求什麼情況該選擇哪種行為.也就是說, 未指定的行為是讓編譯器實現者做選擇題. 但沒有要求其選擇必需是一致的, 編譯器可以在同一個編譯單元中, 一會兒選擇這種做法, 一會選擇另外的做法.
久負盛名的C FAQ(中譯名稱是<<你必須知道的495個C語言問題>>)中關於這個問題, 也有相關的討論

這裡把unspecified的翻譯為"不確定的", 我覺得有些不妥, 這裡的解釋說, unspecified, 跟未定義類似, 但無需提供文檔. 這加劇了我的一些迷惑, 原因是這個C FAQ應該也是相當的權威. "類似"是個模糊的詞, 不中心解惑這個問題. 另外, 至少unspecified 在一些明確的方面和未定義不同, 那就是, 實現者的行為上限是編譯失敗(包括編譯失敗), 雖然我想不出一個編譯器所能引起的比編譯失敗更嚴重的後果,
但正如它所說, 未定義行為比你想象的還要未定義, 或許它可以讓電腦死機, 引發太陽黑子.
該書中的最後陳述乍一看很有建設性. 那就是, 不管這三種行為誰是誰, 你全都要避免踩到雷區. 要求也不小, 你要能記住語言中所有的 implement-defined, unspecified, undefined的行為. 不容易.
但是, 看了The New C standard之後, 就會知道, 要避免所有的unspecified行為幾乎不可能, 比如b+c 表達中, b和c誰先被讀取就是未指定的. 該書中說:

A blanket guideline recommendation prohibiting the use of any construct whose behavior is unspecified would be counterproductive.
光是 unspecified 的行為, 我統計了一下, 50條(統計完這個我發現<<The New C standard>>中就有這麼一句話, 所以我只統計了這一個, undefined的個數是直接從該書引用了, 190個. )
從這50條分析來看, 並非所有的未指定行為, 都是在語言標準中給了可選方案, 讓實現者做選擇就可以了, 比如對靜態變數的初始化的方式和時機. 標準中就沒有給出任何建議的方案.
下面我把C99 標準中的這幾頁PDF 抽出來, 單存成一個檔案. 有興趣的可以自己看看.
檔案: C99_unspecified_behavior.pdf
大小: 53KB
下載: 下載
關於這三個概念, 在C-A reference manual中怎麼解釋, 不幸的是, 我搜遍了這本書的PDF檔案, 找到的多處unspecified, 都不是解釋這個概念本身的. 也許這本書中沒有對此的解釋.
現在, 除了C-A reference manual一書, 我們還有The New C Standard(這本電子書可以在網上免費下載.), 一本逐句解釋ANSI C標準, 長度超1600頁的大部頭經典.
讀了相關的解釋, 果然受用, 整個事態逐漸明朗了.
這本書的注釋澄清了下面的幾個問題:我一開始以為的 implement-defined行為是三者之中最穩定可靠的, 這種想法是不對的, unspecified行為有多種原因, 一種原因是雖然某些行為的細節是unspecified的, 但整個程式的輸出對於所有可能的unspecified行為卻可能不受影響, 有些行為如果要明確指定, 則需要描述當時的上下文環境,
控制流程的分析, 運算式的樹結構, 代碼最佳化演算法, 所以雖然理論上可以對推測出象求值順序這樣問題, 但這麼做是很不現實的.
另一個澄清的問題是, unspecified與undefined的一個重要區別是, 前者是針對合法的程式, 後者則是針對非法的程式.
The New C standard, 名字有些誤導, 它不是在定義另一個新的C語言標準, 而是全景式地解讀既有的C99標準. 強烈推薦給拿C當回事的程式員放在手邊參考. 個人認為有了這本書, 普通人讀ANSI C標準不再是那麼痛苦的事了.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.