为什么C和C ++没有提供一组实现提供的操作来执行提供溢出检查的每个基本整数操作(例如bool safeAdd(int *out, int a, int b)
)。
据我了解,大多数指令集都有办法判断操作是否溢出(例如x86溢出和进位标志),并且在有符号整数的情况下也会发生定义。
因此,编译器是否应该能够做得更好,创建更简单,更快速的操作,而不是用C和C ++编写代码?
答案 0 :(得分:10)
C和C ++遵循“你不为你不需要的东西买单”的核心原则。因此,默认的算术运算不会偏离底层架构的算术运算单指令。
至于为什么没有标准库函数来添加两个整数和检测溢出,我不能说。首先,似乎语言将有符号整数溢出定义为undefined behavior:
在C编程语言中,带符号的整数溢出会导致未定义的行为,
考虑到有多种方法可以实现有符号整数(一个补码,两个补码等),并且在创建C时,这些架构都很普遍,可以理解为什么这是未定义的。如果没有关于底层平台的大量信息,很难实现“安全*”纯C 功能。它可以在逐个CPU的基础上完成。
仍然没有让它变得不可能。如果有人能够通过更安全的溢出助手找到C或C ++标准组织的提案并且能够看到他们被拒绝的原因,我肯定会感兴趣。
无论如何,实际上有many ways来检测算术溢出和库以提供帮助。
答案 1 :(得分:6)
可能是因为没有需求。算术溢出是 未定义的行为,表示允许实现这样做 检查。如果编译器供应商认为这样做会卖得更多 编译器,他们会的。
在实践中,编译器执行它们将非常非常困难
比程序员更有效。这几乎是标准的
验证所有数字输入范围的过程,范围在哪里
你可以证明以后的操作不会溢出。都好
程序员这样做是为了习惯。所以这意味着快速if
输入后立即进行,不再进一步检查。
然而,众所周知程序员会犯错误,而且很简单 稍后更改计算时忘记更正验证。 我想在编译器中看到这样的功能。但显然,它不会 帮助销售编译器,或者至少供应商认为它不会,所以 我们不明白。
答案 2 :(得分:6)
这个问题会定期出现。
首先,请记住,C被定义为便携式和高效。因此,它被设计为仅提供由 lot 硬件支持的操作(可能在x86之前甚至看到了光明之前)。
其次,许多编译器为这些操作提供了(or plan to provide)内置函数,因此用户可以使用使用这些内置函数的类类型。内置函数的实现质量并不那么重要(尽管它是这样),而事实上编译器意识到的含义可能会在它们可证明无用时优化检出。
最后,还有其他方法来实际检查程序。例如,静态分析或special compilations modes&单元测试可以及早发现这些缺陷,并避免(或多或少完全)在Release版本中嵌入这些溢出检查的需要。
答案 3 :(得分:5)
因为很少需要它。你什么时候需要检测整数溢出?在几乎所有情况下,当您需要检查某个范围时,通常需要定义实际范围,因为此范围完全取决于应用程序和算法。
您何时真的需要知道结果是否溢出int
范围而不是知道结果是否在特定算法的允许域内,或者索引是否在数组范围内?是你给变量一个语义,语言规范只提供类型的整体范围,如果你选择的范围不符合你的需要,那么这就是你的错。
整数溢出是UB,因为你很少关心它。如果我的unsigned char
在操作期间溢出,我可能选择了错误的类型来累积1000万个数字。但是在运行期间了解溢出对我没有帮助,因为无论如何我的设计都被打破了。
答案 4 :(得分:4)
为什么呢?好吧,因为当C ++从那开始时它们不在C中,并且因为从那以后没有人提出这样的功能并且成功地说服编译器制造商和委员会成员它们足够有用以提供它们。
请注意编译器do provide这类内在函数,因此并不是他们反对它们。
请注意,有一些命题可以标准化Fixed-Point Arithmetic和Unbounded-Precision Integer Types之类的内容。
所以可能只是因为没有足够的兴趣。
答案 5 :(得分:4)
更好的问题可能是:为什么整数溢出未定义的行为?实际上,99.9%的CPU使用二进制补码和进位/溢出位。因此在现实世界中,在汇编程序/操作码级别上,整数溢出始终是明确定义的。事实上,很多汇编程序或与硬件相关的C在很大程度上依赖于明确定义的整数溢出(特别是计时器硬件的驱动程序)。
在标准化之前,原始的C语言可能没有详细考虑这样的事情。但是当C由ANSI和ISO标准化时,他们必须遵循某些标准化规则。 ISO标准不允许偏向某种技术,从而在竞争中赋予某些公司优势。
所以他们不得不考虑一些CPU可能实现一些不完整的东西,比如一个补码,“符号和幅度”或“一些实现定义的方式”。他们必须允许签名的零,填充位和其他模糊的有符号整数机制。
因此,签名数字的行为变得非常模糊。当C中的有符号整数溢出时,您无法判断会发生什么,因为有符号整数可能以二进制补码,一个补码或某些其他实现定义的疯狂来表示。因此,整数溢出是未定义的行为。
这个问题的理智解决方案不是发明一些安全范围检查,而是说明C语言中所有有符号整数都应该有两个补码格式,故事结束。然后一个unsigned char将始终为0到127并溢出到-128,一切都将被很好地定义。但人为的标准官僚机构阻止了标准的转变。
C标准中有很多这样的问题。对齐/填充,endianess等。