【发布时间】:2010-08-25 19:17:04
【问题描述】:
EDIT 公共卫生警告 - 此问题包含关于未定义行为的错误假设。查看已接受的答案。
在阅读recent blog post 之后,我一直在思考在 C 和 C++ 代码中避免所有标准未定义假设的实用性。这是一个从 C++ 中提取的 sn-p,用于进行无符号 128 位加法...
void c_UInt64_Pair::operator+= (const c_UInt64_Pair &p)
{
m_Low += p.m_Low;
m_High += p.m_High;
if (m_Low < p.m_Low) m_High++;
}
这显然依赖于关于溢出行为的假设。显然,大多数机器都可以支持正确类型的二进制整数(尽管可能从 32 位块构建或其他),但优化器显然越来越有可能利用此处的标准未定义行为。也就是说,m_Low < p.m_Low 条件可以通过的唯一方法是 m_Low += p.m_Low 溢出,这是未定义的行为,因此优化器可以合法地确定条件 always 失败。在这种情况下,这段代码就被破坏了。
因此问题是……
如何在不依赖未定义行为的情况下编写上述的合理有效版本?
假设您有一个适当的 64 位二进制机器整数,但您有一个恶意编译器,它总是以最坏可能(或不可能)的方式解释您未定义的行为。此外,假设您没有有一些特殊的内置、内在、库或任何东西可以为您做这些。
编辑 次要澄清 - 这不仅仅是检测溢出,还确保 m_Low 和 m_High 最终得到正确的模 2^64 结果,这也是标准未定义的。
【问题讨论】:
-
1/这不是C。为什么你把这个问题标记为“C”? 2/ 如果这是 C,甚至在 C++ 中,这将不依赖于未定义的行为:无符号整数类型溢出已定义并具有模行为:C99 标准中的 6.2.5.9。
-
@Pascal:实际上,请参阅最新草案的第 5.4 节(我这里没有 C++03 标准,但我相信行为没有改变)--“如果在表达式的求值,结果未在数学上定义或不在其类型的可表示值范围内,行为未定义。"
-
@Pascal - (1) 问题同样与 C 和 C++ 有关。仅提供一个示例并不意味着问题仅与该示例有关。 (2) 那是什么时候发生的?如果是真的,那就是答案(C++ 可能还没有导入相关的 C 规则,但如果没有,它无疑会),所以把它放在一个带有参考的答案中,我会接受。
-
好吧,在看到许多“C/C++”问题后,这有点下意识的反应。对于诸如此类的微妙问题,它们根本不能被认为是同一种语言。请记住我的评论只有“在 C99 中,此代码将被定义”部分。
-
@Steve314:你知道这两者是一样的吗?在这种特殊情况下,我相信它是。在其他情况下,它不是。假设您要询问
'a'的类型,例如:C 和C++ 中的不同答案。
标签: c++ c integer-overflow