当试图在C中存储高于32,767的短整数值时,为了看看会发生什么,我注意到打印到屏幕上的结果是我想要存储的数字, - 65,536。例如。如果我尝试在一个短变量中存储65,536,则打印到屏幕上的数字为0.如果我尝试存储32,768,我会在屏幕上打印 -32,768 。如果我尝试存储65,546并将其打印到屏幕上,我会得到10.我认为你得到了图片。为什么我看到这些结果?
答案 0 :(得分:8)
使用Twos Complement存储整数值。在二进制补码中,可能值的范围是-2^n
到2^n-1
,其中n是用于存储的位数。由于存储的完成方式,当您超过2^n-1
时,最终会回到2^n
。
短片使用 16位(数字存储为15位,最后一位为符号)。
编辑:请记住,不保证会发生此行为。编程语言可能完全不同。从技术上讲,高于或低于最大/最小值是未定义的行为,应该这样对待。 (感谢Eric Postpischil让我保持警惕)
答案 1 :(得分:1)
当值转换为有符号整数类型但无法在该类型中表示时,会发生溢出,并且行为未定义。通常看到结果就像使用了二进制补码编码一样,并且好像存储了低位(或者等价地,该值被包装为两个的适当幂)。但是,您不能依赖此行为。 C标准说,当发生有符号整数溢出时,行为是未定义的。所以编译器可能会以令人惊讶的方式行事。
考虑这个代码,为short int
为16位的目标编译:
void foo(int a, int b)
{
if (a)
{
short int x = b;
printf("x is %hd.\n", x);
}
else
{
printf("x is not assigned.\n");
}
}
void bar(int a, int b)
{
if (b == 65536)
foo(a, b);
}
如果foo
在b
的范围内,请注意short int
本身就是一个非常精细的功能。并且bar
是一个非常精细的函数,只要它仅在a
等于零或b
不等于65536的情况下调用。
虽然编译器在foo
内嵌入bar
,但它可能会从b
此时必须为65536的事实推断出来,short int x = b;
中会出现溢出1}}。这意味着从未采用此路径(即a
必须为零)或允许任何行为(因为溢出时的行为未被C标准定义)。在任何一种情况下,编译器都可以省略此代码路径。因此,为了优化,编译器可以省略此路径并仅为printf("x is not assigned.\n");
生成代码。如果您随后执行了包含bar(1, 65536)
的代码,则输出将为“x未分配。”!
编译器确实对此类进行了优化:观察到一个代码路径具有未定义的行为意味着编译器可能会断定代码路径从未被使用过。
对于观察者来说,为short int
分配过大的值会导致执行完全不同的代码。