在预先存在的“语言”(方言家族)中,编写 C 标准来描述,实现通常会通过执行底层平台所做的任何事情来处理有符号整数溢出,将值截断为底层类型的长度(这就是大多数平台都这样做了),即使是在本来会做其他事情或触发某种形式的信号或诊断的平台上也是如此。在 K&R 的“The C Programming Language”一书中,该行为被描述为“机器相关”。
尽管该标准的作者在已发布的基本原理文档中指出了一些他们期望普通平台的实现会以普通方式运行的情况,但他们不想说某些操作会在某些平台上定义行为但在其他平台上没有定义. 此外,将行为表征为“实现定义的”会产生问题。考虑类似的事情:
int f1(void);
int f2(int a, int b, int c);
int test(int x, int y)
{
int test = x*y;
if (f1())
f2(test, x, y);
}
如果整数溢出的行为是“实现定义的”,那么任何可能引发信号或具有其他可观察到的副作用的实现都需要在调用 f1() 之前执行乘法,即使乘法的结果将被忽略除非 f1() 返回非零值。将其归类为“未定义行为”可以避免此类问题。
不幸的是,gcc 将分类解释为“未定义的行为”,以邀请以不受普通因果律约束的方式处理整数溢出。给定一个函数,如:
unsigned mul_mod_32768(unsigned short x, unsigned short y)
{
return (x*y) & 0x7FFFu;
}
尝试用x
大于调用它INT_MAX/y
可能会任意破坏周围代码的行为,即使函数的结果不会以任何可观察的方式使用。