没有得到整数溢出
Not getting Integer Overflow
假设我想打印一些值。我假设如果我的签名变量超过 TMin
和 TMax
我应该得到整数溢出(在这种情况下,使用 4 字节 int,0x7FFFFFFF
作为 Tmax
和 0x80000000
as Tmin
) 但在这些示例中,我没有得到我期望的结果(在评论中解释):
// Tmax = 0x7FFFFFFF == 2147483647
// Tmin = 0x80000000 == -2147483648
printf("1- overflow test: %d\n", 0x7FFFFFFF+1 ); // overflow - how compiler finds out it's a signed value, not an Unsigned one
printf("2- overflow test: %d\n", 0x80000000-1 ); // in contrast, why I am not getting an integer overflow here
printf("3- overflow test: %d\n", (int) 0x80000000-1 ); // overflow (Expected)
printf("4- overflow test: %d\n",(int) (0x7FFFFFFF+1)); // overflow (Expected)
首先,让我告诉你,(有符号)整数溢出调用undefined behavior。
在那种情况下,任何事情都有可能发生。您既不能相信也不能证明具有 UB 的代码的输出。
澄清一下,甚至
printf("2- overflow test: %d\n", 0x80000000-1 );
是UB。虽然 0x80000000-1
是 unsigned
并且本身不是溢出,但使用 %d
会导致类型不匹配,这在技术上会导致 UB。
关于未定义的行为,来自C11
,附件§J.2,
Conversion to or from an integer type produces a value outside the range that can be
represented.
尝试调用整数溢出是未定义的行为。按照标准,在这种情况下,任何事情都可能发生,包括外在出现的非溢出。此输出的内容无趣且无关紧要。
可能是你的编译器优化掉了。可能是你的系统拒绝以这种方式使用,也可能是一袋米落在中国造成了蝴蝶效应,导致了这种情况。它没有定义那里发生的事情。
也可能是您的系统决定它的整数更大。 c 中仅规定了整数大小的下限(2 字节)(标准计算机通常至少为 4)。您的系统可能有 8 字节整数,甚至更大。
OP 并不总是遇到有符号整数溢出 - 这是未定义的行为。
以下是无符号数学,因为 0x80000000
可能是无符号整数。十六进制常量是最先适合的类型int, unsigned, long, unsigned long, ...
printf("2- overflow test: %d\n", 0x80000000-1 );
0x80000000-1
是无符号类型,因为 0x80000000
首先适合无符号类型,可能 unsigned
的值为 2147483648u
。 2147483648u - 1
--> 2147483647u
.
0x7FFFFFFF+1
是有符号类型,因为 0x7FFFFFFF
首先适合有符号类型,可能 int
的值为 INT_MAX
.
int
+ int
--> int
and INT_MAX + 1
--> 溢出.
OP说“0x80000000 as Tmin”肯定是个误会。在C中,对于32位的int/unsigned
,0x80000000
是一个十六进制常量,其值为2147483648
。对于 OP,Tmin 更有可能 -INT_MAX - 1
.
C 在数字异常方面有点不一致。
有一些您可以做的事情几乎总是会导致问题。如果除以 0,您的程序通常会严重崩溃,就像您访问了一个无效指针一样。
您可以做一些保证不会引起问题的事情。如果你说
unsigned int i = UINT_MAX;
然后加1,保证回绕到0。
还有很多行为是未定义或未指定的。有符号整数溢出就是其中之一。严格来说它是未定义的(任何事情都可能发生,你不能依赖它)。实际上,大多数计算机都悄悄地循环,就像无符号算术一样。
现在,我所说的一切都是关于程序的 运行 时间行为,但在这个问题的已发布代码片段中,所有算术运算都发生在编译时。编译时算法主要根据与 运行-time 相同的规则运行,但并非总是如此。现代编译器往往会警告您有问题的编译时算法(我的 gcc 副本会针对发布的片段发出三个警告),但并非总是如此。
假设我想打印一些值。我假设如果我的签名变量超过 TMin
和 TMax
我应该得到整数溢出(在这种情况下,使用 4 字节 int,0x7FFFFFFF
作为 Tmax
和 0x80000000
as Tmin
) 但在这些示例中,我没有得到我期望的结果(在评论中解释):
// Tmax = 0x7FFFFFFF == 2147483647
// Tmin = 0x80000000 == -2147483648
printf("1- overflow test: %d\n", 0x7FFFFFFF+1 ); // overflow - how compiler finds out it's a signed value, not an Unsigned one
printf("2- overflow test: %d\n", 0x80000000-1 ); // in contrast, why I am not getting an integer overflow here
printf("3- overflow test: %d\n", (int) 0x80000000-1 ); // overflow (Expected)
printf("4- overflow test: %d\n",(int) (0x7FFFFFFF+1)); // overflow (Expected)
首先,让我告诉你,(有符号)整数溢出调用undefined behavior。
在那种情况下,任何事情都有可能发生。您既不能相信也不能证明具有 UB 的代码的输出。
澄清一下,甚至
printf("2- overflow test: %d\n", 0x80000000-1 );
是UB。虽然 0x80000000-1
是 unsigned
并且本身不是溢出,但使用 %d
会导致类型不匹配,这在技术上会导致 UB。
关于未定义的行为,来自C11
,附件§J.2,
Conversion to or from an integer type produces a value outside the range that can be represented.
尝试调用整数溢出是未定义的行为。按照标准,在这种情况下,任何事情都可能发生,包括外在出现的非溢出。此输出的内容无趣且无关紧要。
可能是你的编译器优化掉了。可能是你的系统拒绝以这种方式使用,也可能是一袋米落在中国造成了蝴蝶效应,导致了这种情况。它没有定义那里发生的事情。
也可能是您的系统决定它的整数更大。 c 中仅规定了整数大小的下限(2 字节)(标准计算机通常至少为 4)。您的系统可能有 8 字节整数,甚至更大。
OP 并不总是遇到有符号整数溢出 - 这是未定义的行为。
以下是无符号数学,因为 0x80000000
可能是无符号整数。十六进制常量是最先适合的类型int, unsigned, long, unsigned long, ...
printf("2- overflow test: %d\n", 0x80000000-1 );
0x80000000-1
是无符号类型,因为 0x80000000
首先适合无符号类型,可能 unsigned
的值为 2147483648u
。 2147483648u - 1
--> 2147483647u
.
0x7FFFFFFF+1
是有符号类型,因为 0x7FFFFFFF
首先适合有符号类型,可能 int
的值为 INT_MAX
.
int
+ int
--> int
and INT_MAX + 1
--> 溢出.
OP说“0x80000000 as Tmin”肯定是个误会。在C中,对于32位的int/unsigned
,0x80000000
是一个十六进制常量,其值为2147483648
。对于 OP,Tmin 更有可能 -INT_MAX - 1
.
C 在数字异常方面有点不一致。
有一些您可以做的事情几乎总是会导致问题。如果除以 0,您的程序通常会严重崩溃,就像您访问了一个无效指针一样。
您可以做一些保证不会引起问题的事情。如果你说
unsigned int i = UINT_MAX;
然后加1,保证回绕到0。
还有很多行为是未定义或未指定的。有符号整数溢出就是其中之一。严格来说它是未定义的(任何事情都可能发生,你不能依赖它)。实际上,大多数计算机都悄悄地循环,就像无符号算术一样。
现在,我所说的一切都是关于程序的 运行 时间行为,但在这个问题的已发布代码片段中,所有算术运算都发生在编译时。编译时算法主要根据与 运行-time 相同的规则运行,但并非总是如此。现代编译器往往会警告您有问题的编译时算法(我的 gcc 副本会针对发布的片段发出三个警告),但并非总是如此。