语义错误

语义错误

问题描述:

编译器能否检测到语义错误?如果不是,何时发现错误?语义错误

据我所知,语义错误是由涉及操作符的操作符数量/类型不正确而导致的表达式错误。

例如:

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

“语义”一词含糊不清,在这些不同的上下文中你遇到了两个略有不同的含义。

第一个含义(您的代码)与编译器如何解释您键入的代码有关。但是对此有不同程度的解释 - 语法是一个层次,其中解释只是决定n1*n2意味着您想要执行乘法。但是这里也有更高层次的解释 - 如果n1是一个整数,并且n2是浮点数,结果是什么?如果我投了它,它应该是圆的,截断的,等等?这些是“语义”问题,而不是语法问题,但有人在某处确定是的,编译器可以为大多数人回答这些问题。

他们还决定,该编译器的限制,以什么可以(也应该!)解释。例如,它可以决定投射到int是截断而不是舍入,但它不能决定当您尝试将数组乘以数字时真正想要的。

(有时,人们决定,他们可以,但是,在Python,[1] * 3 == [1,1,1]。)

第二层含义指的是范围更广。如果该操作的结果应该发送到可以取值为0x000到0xFFF的外围设备,并且将0x7FF乘以0x010,那么显然你已经犯了语义错误。外围设备的设计者必须决定是否或如何应对这种情况。作为程序员,你也可以决定进行一些理智检查。但编译器不知道这些外部约束,或者如何执行它们(过滤用户输入?返回一个错误?truncate?wrap?),这是第二个引号的意思。

“语义错误”是“逻辑错误”的另一个术语,您在字面上写错了代码。例如,编写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

语义错误是所有这些,你的代码做一些事情你不打算。

这些错误可以通过测试或分析来捕获。

分析意味着您或工具查看您的代码并尝试找出问题。这涉及使用代码评论和静态分析器。

测试是当您给程序某些输入时,如果程序在语义上是正确的,那么这些输入会产生给定的输出。所以如果实际的输出不符合预期的输出,程序在语义上是不正确的。

所以简单地说,它是你的开发人员或测试人员应该捕捉语义错误。

实际上,相乘的字符串和一个整数是因为不兼容的类型(例如,字符串,整数)的乘法句法错误未在C.定义

语义误差是发生时的错误你的程序确实会编译,但不会做你想做的。

该报价正在谈论的事情,如做一个x <= 1你真的应该做的x < 1

但是对于语言的语义(不允许添加字符串和整数),是的,它是编译器处理它。

这是一个语法错误,编译器可以检测并报告。

语义错误更类似于编译好的东西(直到非常类型),但不是你想要的东西。语义错误是您算法的一部分,而不是您的实际语法。

如果不是编译器,谁检测到这些错误?

有时候,没有人:编译器不需要插入任何运行时检查,当它发生时可以帮助注意到错误,并且执行才会继续。

有时,执行环境:程序因错误而访问无效地址,并且它位于进程可合法访问的地址空间之外。

您可以使用一个静态分析仪配合编译器检测到一些或所有错误的程序,但这些也可以有误报:他们可能会发出警告的一段代码,没有错误的工作原理。

我认为写这本书的作者定义了“语义”的不同。对于大多数编译器来说,有一个步骤涉及一些semantic checks

语义分析是编译器将语义信息添加到分析树并构建符号表的阶段。此阶段执行语义检查,如类型检查(检查类型错误)或对象绑定(将变量和函数引用与其定义关联)或明确赋值(要求所有局部变量在使用前初始化),拒绝不正确的程序或发布警告。语义分析通常需要一个完整的分析树,这意味着这个阶段在逻辑上遵循分析阶段,并且在逻辑上位于代码生成阶段之前,尽管在编译器实现中通常可以将多个阶段折叠到一个代码中。

事实上(因为没有string型C,但只有char*)可以很好地繁殖n1n2。该操作是合法的,定义良好,这就是编译器不会发出错误的原因。

逻辑上(语义上)该语句很少有意义,所以它很可能是编码错误。回答你的问题:你有责任检测和修复这类错误。

+0

GCC拒绝编译''123“* 3'。 – detly 2010-05-12 06:51:00

字符串文字和字符串在内存中以数字(字节/米字或高级别 - 短裤,整数)显示。 C是低级编程级别,其中所有的东西都接近机器/汇编器级别。因此,字符串文字(如果它是数组,它将是不正确的)上的数字的乘法是正确的,因为这个字符串文字实际上(编译后)是一个数字。

基本上有三种类型的错误。

1)语法错误。这些是编译器无法理解的无效代码,例如你用C中的一个整数乘以字符串的例子。编译器检测它们,因为它不能编译它们。

2)语义错误。这些是编译器可以理解的有效代码,但它们不是程序员所打算的。这些可能会使用错误的变量,错误的操作或错误顺序的操作。编译器无法检测到它们。

还有第三类,这可能是最昂贵的:

3)设计错误。代码是正确的,没有错误,并且完全符合你的意图。但你的意图是错误的,例如基于错误的假设,错误的模型,或者你使用了错误的公式,误解了客户等等。

+0

真的,有三种类型的错误,而不是四五个?多么令人惊讶的是乔希麦克道尔的“三难论证”。软酱。考虑:运行时错误,例如Ctrl-C或SIGPWR。是的,没有预测到每个运行时错误都可能被归入“语义”或“设计”之下,但是运行时错误本身只是为了支持您过于自信的答案。还有文档错误。 – 2010-07-06 14:18:18