2010-05-12 28 views
4

編譯器能否檢測到語義錯誤?如果不是,何時發現錯誤?語義錯誤

據我所知,語義錯誤是由涉及操作符的操作符數量/類型不正確而導致的表達式錯誤。

例如:

n3=n1*n2;//n1 is integer, n2 is a string, n3 is an integer 

上面的語句是語義上不正確。

但是在讀Ç的Primer Plus由斯蒂芬·普拉塔我發現下面的語句

編譯器不會檢測語義錯誤,因爲只要不違反規則Ç。編譯器無法預測你的真實意圖。這讓你找到這些類型的錯誤。一種方法是比較一個程序的功能和你期望的功能。

如果不是編譯器,誰檢測到這些錯誤?

我錯過了什麼嗎?

+0

你的例子不是語義錯誤 - 這是一個語法錯誤。即使字符串* int有效(可能意味着n次重複字符串),類型也不兼容。 – Bevan 2010-05-12 05:38:23

+0

@Bevan,術語有時可以以不同的方式使用,而「語義錯誤」似乎就是其中之一。我肯定會稱這是一個語義錯誤,我絕對不會把它稱爲語法錯誤。 (請看下面我對邁克爾的回答的評論。) – 2010-05-12 06:49:19

+0

@托馬斯 - 我看到(並且承認)你的觀點。我以OP Prata引用的精神使用術語「語義」。 – Bevan 2010-05-12 08:59:31

回答

5

「語義」一詞含糊不清,在這些不同的上下文中你遇到了兩個略有不同的含義。

第一個含義(您的代碼)與編譯器如何解釋您鍵入的代碼有關。但是對此有不同程度的解釋 - 語法是一個層次,其中解釋只是決定n1*n2意味着您想要執行乘法。但是這裏也有更高層次的解釋 - 如果n1是一個整數,並且n2是浮點數,結果是什麼?如果我投了它,它應該是圓的,截斷的,等等?這些是「語義」問題,而不是語法問題,但有人在某處確定是的,編譯器可以爲大多數人回答這些問題。

他們還決定,該編譯器的限制,以什麼可以(也應該!)解釋。例如,它可以決定投射到int是截斷而不是舍入,但它不能決定當您嘗試將數組乘以數字時真正想要的。

(有時,人們決定,他們可以,但是,在Python,[1] * 3 == [1,1,1]。)

第二層含義指的是範圍更廣。如果該操作的結果應該發送到可以取值爲0x000到0xFFF的外圍設備,並且將0x7FF乘以0x010,那麼顯然你已經犯了語義錯誤。外圍設備的設計者必須決定是否或如何應對這種情況。作爲程序員,你也可以決定進行一些理智檢查。但編譯器不知道這些外部約束,或者如何執行它們(過濾用戶輸入?返回一個錯誤?truncate?wrap?),這是第二個引號的意思。

5

「語義錯誤」是「邏輯錯誤」的另一個術語,您在字面上寫錯了代碼。例如,編寫n3=n1*n2時,你真的想分割 - 編譯器無法告訴你的算法應該分裂,而不是乘法;你告訴它要繁殖,所以它確實如此。

你在你的例子描述的錯誤是一種安全的錯誤,以及編譯器可以捕捉,他們在類型檢查階段(如果語言是強類型)

+2

這取決於你如何使用單詞,我認爲大多數編譯器的人會不同意這個答案。編譯器通常被視爲由多個「階段」組成。一種是語法分析,通常稱爲「分析器」,它可以捕捉到語法錯誤。這個例子不是語法錯誤。另一個階段是語義分析,它主要處理數據類型,並且可以捕獲類型錯誤,比如這個。因此,這種類型的錯誤通常被稱爲語義錯誤。 – 2010-05-12 06:45:54

+0

@Thomas這解釋了OP在哪裏聽到它;該術語顯然被用於不同的方面,正如[Wikipedia定義](http://en.wikipedia.org/wiki/Semantic_error)那樣,我說 – 2010-05-12 07:23:53

1

語義錯誤是所有這些,你的代碼做一些事情你不打算。

這些錯誤可以通過測試或分析來捕獲。

分析意味着您或工具查看您的代碼並嘗試找出問題。這涉及使用代碼評論和靜態分析器。

測試是當您給程序某些輸入時,如果程序在語義上是正確的,那麼這些輸入會產生給定的輸出。所以如果實際的輸出不符合預期的輸出,程序在語義上是不正確的。

所以簡單地說,它是你的開發人員或測試人員應該捕捉語義錯誤。

0

實際上,相乘的字符串和一個整數是因爲不兼容的類型(例如,字符串,整數)的乘法句法錯誤未在C.定義

語義誤差是發生時的錯誤你的程序確實會編譯,但不會做你想做的。

0

該報價正在談論的事情,如做一個x <= 1你真的應該做的x < 1

但是對於語言的語義(不允許添加字符串和整數),是的,它是編譯器處理它。

0

這是一個語法錯誤,編譯器可以檢測並報告。

語義錯誤更類似於編譯好的東西(直到非常類型),但不是你想要的東西。語義錯誤是您算法的一部分,而不是您的實際語法。

0

如果不是編譯器,誰檢測到這些錯誤?

有時候,沒有人:編譯器不需要插入任何運行時檢查,當它發生時可以幫助注意到錯誤,並且執行纔會繼續。

有時,執行環境:程序因錯誤而訪問無效地址,並且它位於進程可合法訪問的地址空間之外。

您可以使用一個靜態分析儀配合編譯器檢測到一些或所有錯誤的程序,但這些也可以有誤報:他們可能會發出警告的一段代碼,沒有錯誤的工作原理。

1

我認爲寫這本書的作者定義了「語義」的不同。對於大多數編譯器來說,有一個步驟涉及一些semantic checks

語義分析是編譯器將語義信息添加到分析樹並構建符號表的階段。此階段執行語義檢查,如類型檢查(檢查類型錯誤)或對象綁定(將變量和函數引用與其定義關聯)或明確賦值(要求所有局部變量在使用前初始化),拒絕不正確的程序或發佈警告。語義分析通常需要一個完整的分析樹,這意味着這個階段在邏輯上遵循分析階段,並且在邏輯上位於代碼生成階段之前,儘管在編譯器實現中通常可以將多個階段摺疊到一個代碼中。

-1

事實上(因爲沒有string型C,但只有char*)可以很好地繁殖n1n2。該操作是合法的,定義良好,這就是編譯器不會發出錯誤的原因。

邏輯上(語義上)該語句很少有意義,所以它很可能是編碼錯誤。回答你的問題:你有責任檢測和修復這類錯誤。

+0

GCC拒絕編譯''123「* 3'。 – detly 2010-05-12 06:51:00

0

字符串文字和字符串在內存中以數字(字節/米字或高級別 - 短褲,整數)顯示。 C是低級編程級別,其中所有的東西都接近機器/彙編器級別。因此,字符串文字(如果它是數組,它將是不正確的)上的數字的乘法是正確的,因爲這個字符串文字實際上(編譯後)是一個數字。

2

基本上有三種類型的錯誤。

1)語法錯誤。這些是編譯器無法理解的無效代碼,例如你用C中的一個整數乘以字符串的例子。編譯器檢測它們,因爲它不能編譯它們。

2)語義錯誤。這些是編譯器可以理解的有效代碼,但它們不是程序員所打算的。這些可能會使用錯誤的變量,錯誤的操作或錯誤順序的操作。編譯器無法檢測到它們。

還有第三類,這可能是最昂貴的:

3)設計錯誤。代碼是正確的,沒有錯誤,並且完全符合你的意圖。但你的意圖是錯誤的,例如基於錯誤的假設,錯誤的模型,或者你使用了錯誤的公式,誤解了客戶等等。

+0

真的,有三種類型的錯誤,而不是四五個?多麼令人驚訝的是喬希麥克道爾的「三難論證」。軟醬。考慮:運行時錯誤,例如Ctrl-C或SIGPWR。是的,沒有預測到每個運行時錯誤都可能被歸入「語義」或「設計」之下,但是運行時錯誤本身只是爲了支持您過於自信的答案。還有文檔錯誤。 – 2010-07-06 14:18:18