使用未定义的溢出创建unsigned int?

时间:2017-06-09 13:13:31

标签: c++

在Chandler Carruth(link)最近39:16左右完成的CppCon演讲中,他解释了如何让未定义的有符号整数的溢出允许编译器生成优化的汇编。 这些优化也可以在Krister Walfridsson撰写的博客文章中找到,here

之前被INT_MAX上出现大小溢出的错误所困扰,我倾向于对我在代码中使用的类型感到迂腐,但与此同时我不想失去相当直接的性能提升。

虽然我对汇编知识有限,但这让我想知道创建一个带有未定义溢出的无符号整数会产生什么影响?这似乎是一个反复出现的问题,但我没有找到任何引入一个(并最终更新std::size_t)的提议,是否曾经讨论过这样的问题?

2 个答案:

答案 0 :(得分:3)

没有未定义溢出的无符号整数。 C ++非常具体,无符号类型不会溢出;他们服从模运算。

该语言的未来版本是否可以添加不遵守模运算的算术类型,但也不支持符号(因此可能使用其整个范围)?也许。但是所谓的性能提升并不是它们带有符号值的原因(否则必须考虑正确处理符号位,而无符号值没有强制执行“特殊”位)所以我不会屏住呼吸。事实上,虽然我不是装配专家,但我无法想象这会以任何方式有用。

答案 1 :(得分:3)

这个问题完全落后了。没有一些神奇的灵丹妙药,通过这种灵丹妙药可以将行为视为未定义,以便为编译器提供优化机会。总有一个偏差。

对于在某些条件下具有未定义行为的操作,C ++标准需要不对结果行为描述任何约束。这是标准中未定义行为的定义。

对于C ++标准(或任何标准 - 未定义的行为是标准的一个特征,而不仅仅是编程语言的标准)来做到这一点,需要有一种以上的实际方法来实现操作,条件,产生不同的结果,优点和缺点。对于不止一种替代方案,还需要有现实实施的现实前景。最后,需要有现实的机会,每个特征提供一些价值(例如,使用这些特征的系统的理想属性等) - 否则可以指定一种方法,并且不需要替代方案。

由于许多影响因素,有符号整数的溢出在溢出时具有未定义的行为。首先,存在有符号整数的不同表示(例如,补码,二进制补码等)。第二,有符号整数的表示(根据定义)包括符号的表示,例如,一个标志位。第三,没有特定的有符号整数的表示,其本身优于另一个(选择一个或其他涉及工程权衡,例如在处理器内设计电路以实现加法操作)。第四,存在使用不同表示的现实世界的实现。由于这些因素,对溢出的有符号整数的操作可以“包裹”#34;使用一个CPU,但会产生必须在另一个CPU上清除的硬件信号。对于某些应用而言,这些类型的行为中的每一种(或其他行为)可能是最佳的,而不是其他应用。标准必须允许所有这些可能性 - 它所采取的手段是认为行为未定义。

对无符号整数运算具有明确定义的行为的原因是因为没有尽可能多的现实方式来表示它们或对它们进行操作 - 当这些表示和操作在CPU电路中实现时,结果所有都是相同的(即模运算)。没有"符号位"担心创建电路来表示和操作无符号整数值。即使无符号变量中的位物理布局不同,操作的实现(例如,使用与非门的加法器电路)在所有基本数学运算(加法,减法,乘法,除法)的溢出上都会产生一致的行为。而且,毫不奇怪,所有现有的CPU都是这样做的。没有一个CPU在无符号溢出时产生硬件故障。

因此,如果您希望对无符号值的溢出操作具有未定义的行为,您首先需要找到一种以某种方式表示无符号值的方法,从而产生多个可行/有用的结果/行为,您的方案在某些方面更好(例如性能,更容易制造的CPU电路,应用程序性能等)。然后,您需要说服一些CPU设计人员实现这样的方案,并说服系统设计人员该方案提供了真实的优势。与此同时,您需要让一些CPU设计人员和系统设计人员相信其他一些方案比其他方案更有优势。换句话说,您的方法的实际使用必须涉及真正的权衡,而不是您的方法比所有可能的替代方案具有一致的优势。然后,一旦你在不同方法的硬件中有多个实现 - 导致不同平台上溢出的不同行为 - 你需要说服C ++标准化委员会在标准中支持你的方案有优势(即语言或库特性)利用你的方法),并且需要允许所有可能的溢出行为。只有这样,无符号整数(或其变体)的溢出才会有未定义的行为。

我已经从硬件级别开始描述了上述内容(即在硬件中对您的无符号整数类型进行本机支持)。如果你在软件中这样做也是如此,但你需要说服开发人员更换库或操作系统。

只有这样,你才会引入一个无符号整数类型,如果操作溢出,它将具有未定义的行为。

更一般地说,正如开头所说,这个问题虽然落后了。确实,编译器利用未定义的行为(有时以非常狡猾的方式)来提高性能。但是,为了使标准认为某些东西具有不确定的行为,需要不止一种方式进行相关操作,并且实现(编译器等)需要能够分析替代方案的好处和权衡,然后 - 根据一些标准 - 选择一个。这意味着总会带来好处(例如性能)和不必要的后果(例如某些边缘情况下的意外结果)。