2013-06-30 31 views
2

当试图在C中存储超过32,767的短整数值时,为了看看会发生什么,我注意到打印到屏幕上的结果是我试图存储的数字 - 65,536。例如。如果我尝试在一个短变量中存储65,536,则打印到屏幕的数字为0.如果我尝试存储32,768,则我将-32,768打印到屏幕上。如果我尝试存储65,546并将其打印到屏幕上,我会得到10个。我认为您可以获得照片。为什么我看到这些结果?短整型值32767以上

+2

短是2个字节(通常取决于)。 2个字节= 16位。第一个是星座,所以可以将其翻转并变为负值之前存储的值达到2^15。 – Dave

+1

HTTP://en.wikipedia。org/wiki/2%27s_complement –

+3

(它对于签名类型实际上是未定义的行为,虽然我从来不知道除了模值之外的任何其他实现) – Dave

回答

8

整数值使用Twos Complement存储。在二进制补码中,可能值的范围是-2^n2^n-1,其中n是用于存储的位数。由于存储完成的方式,当你高于2^n-1时,你最终会回到2^n

短裤使用16位(15位用于数字存储,最后一位是符号)。

编辑:请记住,此行为不保证发生。编程语言的行为可能完全不同。从技术上讲,高于或低于最大值/最小值是未定义的行为,应该这样处理。 (感谢Eric Postpischil保持我的脚趾头)

+2

行为是未定义的。你不能依靠补码。即使底层硬件使用二进制补码,编译器中的优化也会导致包含溢出的代码被忽略或以令人惊讶的方式进行更改。 –

+1

这是正确的,但他看到他所看到的是底层Twos Complement没有被抽象或优化的原因。绝对不是依靠行为,而是可以解释的行为。 –

+1

然后答案应明确说明。请记住,这个答案是持久的,可能会被许多其他人想要了解类似的问题。在没有限定的情况下表示使用二进制补码存储整数值是错误的,并且即使在底层硬件中为真时,也是误导性的,因为语言规则不需要C语言中的溢出来产生与二进制补码中的溢出相同的行为。 –

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是一个完全正常的功能,只要在编译器中衬里foobar它被称为只a等于零或b不等于65536

,它可以从事实推断b在这一点上必须是65536,那么在short int x = b;中将会出现溢出。这意味着要么永远不会采用此路径(即,a必须为零),要么允许任何行为(因为溢出时的行为未由C标准定义)。无论哪种情况,编译器都可以自由地省略这段代码路径。因此,为了优化,编译器可以省略此路径并仅为printf("x is not assigned.\n");生成代码。如果您随后执行包含bar(1, 65536)的代码,则输出将为“x未分配”。

编译器做使这种优化:一个代码路径已不确定的行为观察意味着编译器可以断定代码路径从未使用过。

对于观察者,它看起来像分配一个过大的值,以一个short int的作用是使被执行完全不同的代码。

相关问题