前几天看到一个程序,一开始觉得涉及数据溢出之类的,觉得蛮有意思的,(32位系统中,我用的是Linux系统)代码如下
#include<stdio.h>
#define MAX 2147483647 //2^31-1
#define MIN -MAX-1
#define min -2147483648 //-2^31
#define max -min
void main()
{
printf("u=%u,x=%d\n",min,min);
printf("u=%u,x=%d\n",max,max);
printf("u=%u,x=%d\n",MIN,MIN);
printf("u=%u,x=%d\n",MAX,MAX);
}
运行结果如下:
是不是特别奇怪???前两行的u相等按理来说机器数也相等,但是为什么十进制输出的结果不一样
这里就涉及到了整数提升:
就是在C99标准中,一个常量的值是多少,
如果在0~2^31 -1这个范围,则将常量看成int型的,
如果在 2^31~ 2^63 -1 ,则看成long long int,
如果在2^63 ~ 2^64 -1,则看成unsigned long long int
而对一个常量进行处理,先提前它的数值进行判断,看是什么类型,然后再结合符号。
从这些我们可以知道,2147483648在这里被看成long long int 型的了,原来int型的4个字节被提升成8字节的long long int
原来的int 型机器数表示 0x80000000
提升以后long long int 表示 0x0000000080000000
这时把符号考虑进去,机器数就变成0xffffffff80000000,这是min的机器数,所以max的机器数就是0x0000000080000000
min和max的低4个字节都是0x80000000,按照无符号的输出都是这个机器数,但是为什么输出的十进制数不一样呢??这说明整数提升以后并没有把这个long long int 截断成int 输出(我以前以为输出会截断的,好蠢)
于是我用gdb进行调试了一下,看了一下他的汇编代码先看第一个printf,会发现,因为整数提升,原来int型一个值只要push一次就可以把值存起来,但是变成8字节的long long int以后,就要分两次push了,所以原来int型两个数push两次,而long long int就要push四次,但是你输出的时候只输出两个数,就是取两个push值,每次都是先取低地址的,所以第一次取的时候是取0x80000000,第二次取0xffffffff,所以输出的时候第一个按无符号输出就是2147483648,而第二个是-1.
再看第二个printf,会发现道理都是一样的,第一次取的时候是取0x80000000,第二次取0x00000000,这就解释了为什么输出的结果会是这样,
如果不信的话还可以直接输出0xf8000000,会发现输出的是2147483648和15.