①在整形家族中有:
char (一个字节)
unsigned char
signed char
short(int 省略)(两个字节)
unsigned short
signed short
int(四个字节)
unsigned int
signed int
long(int 省略)(四个字节)//在早期老设备int是两个字节,所以称之为长整形,而现在long与int长度一致
unsigned long
signed long
long long 同(八个字节)
注意:只有char类型的数据类型由不同编译器环境决定默认为无符号还是有符号
其他均默认为有符号,vs环境下char为有符号
②整形在内存中存储:补码(二进制的形式)(小提一手)
在vs中,调试内存窗口这里,是按字节为单位有序排列(这里是按十六进制(容易看),ox为十六进制前缀)
(a~f代表10~15)
两个十六进制位刚好代表一个字节八个二进制位(通过数学知识,我们只需要在对应的每八个二进制与对应的每两个十六进制相互转化就好)(其他进制就没有这么好的性质)
补码来运算,非常的方便,最主要是不影响结果
③符号与无符号:
unsigned 无符号:没有符号位,恒为正
signed 有符号:补码首位为1则为为负
其他进制的数的正负取决于首位,例如十六进制,首位0~7则位正,8~15为负,(一半数为正,一半数为负)
结合类型的字节数,导致他们拥有了一个“闭环的”取值范围
(例如char)
其他类型可类推(超出范围就会截断,-这导致出现了取值范围)
④整形在内存中以补码的形式存储.
对于正数和无符号数,他们的原码反码补码相同;
对于负数,
例如 (int)-1
原码(给人看的,直接得到到二进制数)(补码取反加一or补码减一取反)
10000000000000000000000000000001
反码(除了符号位,按位取反)
1111111111111111111111111111111111110
补码(计算机内存中看到的,计算机认识的,计算机识别的)(原码取反加一)
1111111111111111111111111111111111111
(如果强制类型转化位unsigned int 则计算机直接识别到的是补码,直接认为是正数)
补充:10000000000000000000000000000000(-2147483648)的原码是三十三位的,但是没关系,内存中是三十二位就好,毕竟字节大小限制的是补码,因为存放的是补码。
注意:其他位数的什么什么码要转化为二进制看
补充:在计算过程中,遇到整形提升和算术转化和截断甚至移位操作符,位数上升(或者补位),有符号整形补符号位,无符号补0,计算过程保持用补码,并且算术表达式最低类型为int,计算结果根据最终要存放在哪个类型中决定补充还是截断。(有时通过闭环取值范围能很好的得到结果)
额外内容:大小端字节序
(大端模式)就是数据的低位存放在高地址处,数据的高位存放在低地址处
(小端模式)就是数据的高位存放在高地址处,数据的低位存放在低地址处(VS环境)
以字节为单位从左往右地址递增,位的值大小也递增(符合习惯)(习不习惯不重要,记住这个规矩就好,并且一些编译器是大端,与此相反)(这跟指针的加法和解引用有关)
下面是一个函数来判断编译器是大端还是小端
void judge() { int i=1; if(*((char*)&i)) printf("小端\n"); else printf("大端\n"); } //其他序列类型被淘汰了
练习:
#include<stdio.h> int main() { unsigned char c=-1; printf("%d",c); return 0; }
这里,-1为整形,则补码为11111111111111111111111111111111,但是是截断后为11111111(无符号255),然后要变为有符号整形int,要补充0,得到00000000000000000000000011111111,就是255.
#include<stdio.h> int main() { char a=-128; printf("%u",a); return 0; }
这里,-128为10000000,整形提升补的是符号位1,为11111111111111111111111110000000,然后被认为是无符号打印出来,就是4294967168
int main() { char a=128; printf("%u",a); return 0; }
这里,把128(......10000000)放到char里面去,(截断后)是-128,而打印成无符号,就跟上一道题一样,先补上符号位1,然后被看做是无符号打印出来。
int main() { int i=-20; unsigned int j=10; printf("%d",i+j); return 0; }
这里,-20为10000000000000000000000000010100
补码 ->111111111111111111111111111111101100
10为00000000000000000000000000001010
-20的补码被看作了无符号,然后与10相加,后为111111111111111111111111111111110110
但是打印的时候计算机识别这个补码,打印为有符号(通过计算出原码知道是-10)
就是说:(需要补位的补位,截断的截断之后)不用管送到占位符那的那个补码的前世今生,根据占位符读这个码,得到多少就是多少。
最后注意了
unsigned int i; for (i = 9; i >= 0; i--) { printf("%u\n", i); }
这是一个死循环,因为0-1后,由于是无符号,它还是大于等于0的!