5 回答
TA貢獻1815條經驗 獲得超13個贊
未定義的行為是C和C ++語言的一個方面,對于來自其他語言的程序員來說可能會令人驚訝(其他語言試圖更好地隱藏它)?;旧希锌赡芫帉懖荒芤钥深A測的方式運行的C ++程序,即使許多C ++編譯器不會報告程序中的任何錯誤!
讓我們看一個經典的例子:
#include <iostream>int main(){
char* p = "hello!\n"; // yes I know, deprecated conversion
p[0] = 'y';
p[5] = 'w';
std::cout << p;}變量p指向字符串文字"hello!\n",下面的兩個賦值嘗試修改該字符串文字。這個程序做什么用的?根據C ++標準的第2.14.5節第11段,它調用未定義的行為:
嘗試修改字符串文字的效果是未定義的。
我可以聽到人們尖叫“但是等等,我可以編譯這個沒問題并得到輸出yellow”或“你的意思是什么未定義,字符串文字存儲在只讀內存中,所以第一次分配嘗試會導致核心轉儲”。這正是未定義行為的問題?;旧希坏┠阏{用未定義的行為(甚至是鼻子惡魔),標準允許任何事情發生。如果根據您的語言心理模型存在“正確”行為,那么該模型就是錯誤的; C ++標準有唯一的投票期。
未定義行為的其他例子包括訪問超出其邊界的數組,解引用空指針,訪問對象后,他們的壽命結束或寫入據說聰明的表情一樣i++ + ++i。
C ++標準的第1.9節還提到了未定義行為的兩個不那么危險的兄弟,未指定的行為和實現定義的行為:
本國際標準中的語義描述定義了參數化的非確定性抽象機器。
抽象機的某些方面和操作在本國際標準中描述為實現定義的(例如,
sizeof(int))。這些構成了抽象機器的參數。每個實施應包括描述其在這些方面的特征和行為的文件。抽象機器的某些其他方面和操作在本國際標準中被描述為未指定的(例如,對函數的參數的評估順序)。在可能的情況下,本國際標準定義了一組允許的行為。這些定義了抽象機器的非確定性方面。
本國際標準中將某些其他操作描述為未定義(例如,取消引用空指針的效果)。[ 注意:本國際標準對包含未定義行為的程序的行為沒有要求。- 結束說明 ]
具體而言,第1.3.24節規定:
允許的未定義行為包括完全忽略不可預測的結果,在翻譯或程序執行期間以環境特征(有或沒有發出診斷消息)的特定行為,終止翻譯或執行(發布時)一條診斷信息)。
你能做些什么來避免遇到未定義的行為?基本上,你必須閱讀那些了解他們所談論內容的作者的優秀C ++書籍。螺絲網絡教程。螺旋公牛隊。
TA貢獻1810條經驗 獲得超5個贊
也許簡單的措辭可以比標準的嚴格定義更容易理解。
實現定義的行為
語言表示我們有數據類型。編譯器供應商指定他們使用的大小,并提供他們所做的文檔。
未定義的行為
你做錯了什么。例如,您有一個非常大的值int,不適合char。你怎么把這個價值放進去char?實際上沒有辦法!任何事情都可能發生,但最明智的做法是將該int的第一個字節放入其中char。分配第一個字節是錯誤的,但這就是幕后發生的事情。
未指定的行為
首先執行這兩個函數?
void fun(int n, int m);int fun1(){
cout << "fun1";
return 1;}int fun2(){
cout << "fun2";
return 2;}...fun(fun1(), fun2()); // which one is executed first?該語言未指定評估,從左到右或從右到左!因此,未指定的行為可能會或可能不會導致未定義的行為,但當然您的程序不應產生未指定的行為。
TA貢獻1877條經驗 獲得超6個贊
for
fun(fun1(), fun2());是不是“實現定義”的行為?畢竟編譯器必須選擇一個或另一個課程?
實現定義和未定義之間的區別在于編譯器應該在第一種情況下選擇一種行為,但在第二種情況下不需要。例如,實現必須只有一個定義sizeof(int)。因此,它不能說sizeof(int)程序的某些部分為4,其他部分為8。與未指定的行為不同,編譯器可以說OK,我將從左到右評估這些參數,并且從右到左評估下一個函數的參數。它可能發生在同一個程序中,這就是為什么它被稱為未指定的原因。實際上,如果指定了一些未指定的行為,C ++可能會變得更容易。看看Stroustrup博士對此的回答:
據稱,為編制者提供這種自由并要求“普通的從左到右的評估”可以產生的差異可能很大。我不相信,但是有無數的編譯器“在那里”利用自由和一些人熱情地捍衛自由,改變將是困難的,可能需要數十年才能滲透到C和C ++世界的遙遠角落。我很失望并非所有編譯器都會對++ i + i ++等代碼發出警告。同樣,參數的評估順序是未指定的。
IMO太多“事物”未定義,未指定,實現定義等。但是,這很容易說,甚至可以提供示例,但很難修復。還應該注意,避免大多數問題并產生可移植代碼并不是那么困難。
TA貢獻1850條經驗 獲得超11個贊
來自官方C理由文件
術語未指定的行為,未定義的行為和實現定義的行為用于對編寫程序的結果進行分類,這些程序的屬性標準不能或不能完全描述。采用這種分類的目的是允許實現中的某種變化,這允許實現的質量成為市場中的主動力量以及允許某些流行的擴展,而不去除與標準的一致性的標記。標準的附錄F對屬于這三個類別之一的行為進行了編目。
未指定的行為使實現者在翻譯程序時具有一定的自由度。只要沒有翻譯程序,這個范圍就不會延伸。
未定義的行為使實現者許可證不會捕獲難以診斷的某些程序錯誤。它還標識了可能符合語言擴展的區域:實現者可以通過提供正式未定義行為的定義來擴充語言。
實現定義的行為使實現者可以自由選擇適當的方法,但需要向用戶解釋此選擇。指定為實現定義的行為通常是用戶可以基于實現定義做出有意義的編碼決策的行為。在決定實施定義應該有多廣泛時,實施者應該牢記這個標準。與未指定的行為一樣,只是無法轉換包含實現定義的行為的源不是一個充分的響應。
- 5 回答
- 0 關注
- 1366 瀏覽
添加回答
舉報
