首先要知道我们的数据是怎么样放入内存的,例如我们int a=2;sizeof(int)=2;那么放入内存的数据为00000000 00000010,假设int a=-2,那么存放为11111111 11111110,始终记住在内存里存放的是补码形式,正数的补码是本身。现在要用printf输出,就先要到内存里面去得到数,假设%d形式输出,则函数根据符号为进行求源码,如果是%u输出则函数认为内存里存放的为无符号数,所以直接输出数字11111111 11111110=65534。
假设我们把一个int赋给char的,那么int 就要被截断了,底8位不动的直接挪给char,例如unsigned char c;
C=a;那么c对应的内存为11111110(当a=-2),当我们输出格式为%d,%u的时候都是254哦,这和unsigned int a=-2不一样,当我们输出格式为%d,%u的时候一个正数,一个负数。
假设我们相反把一个char赋给int,那么就要进行符号扩展了,谭书上60页说了:
如果把字符处理为无符号的,那么int的高位全部补0;
如果把字符处理为有符号的,那么int的高位与char放在内存的数据的最高为扩展,例如char c=-2,在内存里面格式为11111110,那么int a=c,a的格式为11111111 11111110,如果char c=2,在内存的存放为00000010,那么int a=c,a的格式为00000000 00000010
记住printf的格式控制是从内存里面取数据,在进行相应的转换的
2
当我们输入数据的时候假设int a=2,那么内存里面高位扩0,但是如果int a=65535,那么16为已经满了它不会写成0 11111111 11111111因为这样已经17位了
一个符号扩展的例子:
typedef struct {
int a:2; 1
int b:2; 2
int c:1; 3
}test;
test t;
t.a = 1; 4
t.b = 3; 5
t.c = 1; 6
printf("%d",t.a); 7
printf("%d",t.b); 8
printf("%d",t.c); 9
谢谢!
t.a为01,输出就是1
t.b为11,输出就是-1
t.c为1,输出也是-1 ---位扩展
解释:a不说,对于b来说,t.b=3,写进内存为11,因为已经满2位了,所以直接进驻内存,不用扩展符号,(不考虑补码的形式),但printf输出的是int型,所以要进行到2到16位的扩展,因为申明的是int b:2;所以高16位字节与b的最高位一样为111111111 11111111,所以输出为%d的形式输出为-1,如果%u的形式,那么输出为65535.
假设我们在第2行中把int b:2,写成unsigned int b:2,那么结果就变了哦,这就导致了进行符号扩展的时候全部补0,结果是在内存的格式就是00000000 00000011输出的两种都为3.
负数的补码
符号位为1,其余位为该数 绝对值的原码按位取反;然后整个数加1。 同一个数字在不同的补码表示形式里头,是不同的。比方说-15的补码,在8位2进制里头是11110001,然而在16位2进制补码表示的情况下,就成了1111111111110001。在这篇补码概述里头涉及的补码转换默认了把一个数转换成8位2进制的补码形式,每一种补码表示形式都只能表示有限的数字。 【例2】求-7的补码。 因为给定数是负数,则符号位为“1”。 后七位:+7的原码(0000111)→按位取反(1111000)→加1(1111001) 所以-7的补码是11111001。 已知一个数的补码,求原码的操作分两种情况: (1)如果补码的符号位为“0”,表示是一个正数,其原码就是补码。 (2)如果补码的符号位为“1”,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。 再举一个例子:求-64的补码 +64:01000000 11000000 【例3】已知一个补码为11111001,则原码是10000111(-7)。 因为符号位为“1”,表示是一个负数,所以该位不变,仍为“1”。 其余七位1111001取反后为0000110; 再加1,所以是10000111。