c - 带符号的长整数随着它的增长变成负数?

标签 c

我正在做一些数学运算,然后像这样打印一个带符号的长整数:

file1.c

#include <stdio.h>

int main (int argc, char *argv[])
{
    long my_signed_integer = 9999L * 9999L * 9999L * 9999L;
    printf("This is my signed integer %ld.\n", my_signed_integer); 

    return 0;
}

生成文件

CFLAGS=-Wall -g

all: file1

clean:
    rm -f file1

我试图看看在我的编译器不向我抛出错误的情况下我能走多远,每次乘法都加一个 9999L,然后运行:

make
./file1.c

看看会发生什么。


4 次

当使用 9999L 4 次时(如上例),我得到:

这是我的有符号整数 9996000599960001。

没有任何警告。


5 次

使用 9999L 5 次,我收到 1 个警告:

warning: overflow in expression; result is 7716289630452291919 with type 'long'
      [-Winteger-overflow]

但是文件还是编译通过了,最终的结果是:

这是我的有符号整数 7716289630452291919。


6 次

使用 9999L 6 次,我收到 2 条警告 - 一条是负数:

warning: overflow in expression; result is 7716289630452291919 with type 'long'
      [-Winteger-overflow]
        long my_signed_integer = 9999L * 9999L * 9999L * 9999L * 9999L * 9999L;
                                                               ^
warning: overflow in expression; result is -7550445434587511647 with type 'long'
      [-Winteger-overflow]
        long my_signed_integer = 9999L * 9999L * 9999L * 9999L * 9999L * 9999L;

唉,文件仍然编译,结果是:

这是我的有符号整数 -7550445434587511647。


随着我添加越来越多的整数,这种模式继续存在 - 我每次都会收到另一个警告。

首先,有人可以解释为什么编译器不会崩溃并拒绝编译文件吗?显然存在溢出 - 为什么可以容忍这种情况,而其他情况 - 例如乘以非常大的数字 - 会使它崩溃?

还有,为什么最后的结果是负整数?

最佳答案

有符号整数类型的溢出是 undefined behavior按照 C 标准。所以编译器可以自由地生成它想要的任何行为。这也意味着是否生成警告是自由的。

在实践中,在使用 2 的整数补码表示的托管实现中,溢出将表现得好像参数是无符号的(因此减少模 2^(位长度))并且结果被解释为有符号。

在您的特定情况下,long 似乎是 64 位类型。因此,将 9999L 本身乘以 4 次适合该类型,但再多一点就会溢出。您获得的值是解释为 signed long 的结果的最低 64 位。

5次的情况下,恰好高位没有置位,所以结果显示为正。在6次的情况下,设置了高位,所以显示为负数。

关于c - 带符号的长整数随着它的增长变成负数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43413311/

相关文章:

c - C 中的这个字符串比较函数有什么问题?字符串是如何比较的?

c++ - 变量的 block 结构内存分配

c - 在一行中输出 C 语言中的 system()

java - Java 中的 CFwapInt32LittleToHost 等效项

c - 无法将 c 代码链接到 lapack/blas : undefined reference

c - 嵌入式 C - 在 switch/case 和 hashtable 之间选择

c - 宏扩展的具体步骤是什么?

c - C 会自动释放函数内分配的内存吗?

c++ - 用于检测音频过零的选项

c - C 中是否可以为结构成员分配不同的内存位置?