我是在编译器里用sizeof(int) 输出 4
说明我这是4个字节32位的编译器。
int a = 0x7fffffff; //有符号的 范围是 -2^31~2^31 = 2147483638 = 0x7fffffff
unsigned int b = ; //无符号的 有符号的话就是 0~2^32 = 4294967296 = 0xffffffff
那么根据c语言的定义
unsigned int
溢出后:数会以2^(8*sizeof(type))作模运算
signed int
溢出后:undefined behavior
所以下面的代码输出为什么是?而且我把变量定义为sign 和 unsigned对输出的结果都没有影响,为什么?
printf("a: %d\n", a); // 输出 a: 2147483647
printf("a: %d\n", a+1); // 输出 a: -2147483648
谢谢大神们的指教!
为了叙述方便,假设只有 3bit 表示一个整数。
一个
signed
的整型,表示范围是 -4 ~ 3,unsigned
是0 ~ 7
。对于signed
型,哪个二进制表示-4 -3 -2 ...
等有多种映射的方式。所以人们需要找一种比较好的方式,最终使用的方式就是现在的补码。表示的方式就是:
这里多说一句对于signed负数a,其对应的二进制的转换成unsigned的b满足关系:
a = b - 8
这个做的好处就是
unsigned
signed
的加法(包括减法)是一样的运算方式。。。比如1+4=5
和1+(-4) = -3
他们的表示二进制都是001+100=101
。所以无论是
unsigned
还是signed
他们其实计算机里都是相同的运算规则(加减法),只是"输出"的时候100
被作为unsigned
被解释为4,signed
被解释为-4
,而变量的类型说明了着一串二进制如何解释对于函数
printf
,你有没有发现,其实他的声明只规定了第一个参数的类型,并没有规定后面参数的类型。这种函数其实是C语言里可变参数的函数类型。printf
是根据第一个参数中的%d
之类的占位参数确定后面有几个参数以及占用了多少个字节。printf("%d %f\n",a,b) 的时候,通过%d
printf
就把第二参数“认为”是signed
占4个字节,然后再就知道了第三个参数的起始地址:所以不论 a 是 unsigned 还是 signed
a = 3(011)
加 1之后都是100
,然后由于%d
的原因printf
把其解释为signed
得到-4
.