当试图在 C 中存储高于 32,767 的短整数值时,为了看看会发生什么,我注意到打印到屏幕上的结果是我要存储的数字 - 65,536。例如,如果我尝试将 65,536 存储在一个短变量中,则打印到屏幕上的数字是 0。如果我尝试存储 32,768,我会得到-32,768打印到屏幕上。如果我尝试存储 65,546 并将其打印到屏幕上,我会得到 10。我想你明白了。为什么我会看到这些结果?
2 回答
整数值使用二进制补码存储。在二进制补码中,可能值的范围是-2^n
到2^n-1
,其中 n 是用于存储的位数。由于存储的方式,当你在上面时2^n-1
,你最终会回到2^n
.
短裤使用16 位(15 位用于数字存储,最后一位是符号)。
编辑:请记住,不保证会发生这种行为。编程语言的行为可能完全不同。从技术上讲,高于或低于最大/最小值是未定义的行为,应该这样对待。(感谢 Eric Postpischil 让我保持警觉)
当一个值转换为有符号整数类型但不能以该类型表示时,会发生溢出,并且行为未定义。通常会看到结果,好像使用了二进制补码编码并且好像存储了低位(或者,等效地,该值以适当的 2 次方为模包装)。但是,您不能依赖此行为。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
. Andbar
是一个非常好的函数,只要它被调用时仅a
等于 0 或b
不等于 65536。
当编译器内联foo
in 时,它可能从此时必须为 65536bar
的事实推断出,在. 这意味着要么永远不会采用这条路径(即,必须为零),要么允许任何行为(因为溢出时的行为未被 C 标准定义)。在任何一种情况下,编译器都可以随意省略此代码路径。因此,为了优化,编译器可以省略此路径并仅为. 如果您随后执行包含 的代码,则输出将是“未分配 x。”!b
short int x = b;
a
printf("x is not assigned.\n");
bar(1, 65536)
编译器确实进行了这种优化:观察到一个代码路径具有未定义的行为意味着编译器可能会得出从未使用过代码路径的结论。
对于观察者来说,给 a 赋值过大的效果似乎short int
是导致执行完全不同的代码。