1.了解一下%u,整型提升,原码反码补码的概念
%u:
以十进制数输出unsigned型数据(无符号数) (在一些的编译器里面会报警告,我们用%zu最合适,sizeof的返回值要用%zu来打印)
ps:char 到底是unsigned 还是signed,c语言标准并没有规定,取决于编译器,但是大部分的编译器还是默认char类型的是signed char;而c语言的标准进行了规定,int类型的就是signed int
整型提升:
C的整型算术运算总是至少以缺省整型类型的精度来进行的;
为了获得这个精度表达式中的字符和短整型操作数在使用之前被转换为普通整型
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
通用CPU(general-purposeCPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsignedint,然后才能送入CPU去执行运算。(所以整型提升针对的是长度小于int的类型)
以上代码说明了整型提升的存在!
那么如何进行整型提升呢?
整型提升是按照变量的数据类型的符号位来提升的
负数的整型提升前补1;而正数的整型提升前补0;
原码,反码,补码:
原码:是机器数中最简单的一种表示形式,第一位为符号位,符号位是0,表示正数,符号位是1表示负数;
反码:出符号位以外,原码取反(0变为1,1变为0)即可得到反码
补码:反码+1得到补码;
2.几个应用实例及原理解释
(1)
int main()
{
char a = -1;
//-1:的二进制位数:10000000000000000000000000000001原码
// 11111111111111111111111111111110反码
// 11111111111111111111111111111111补码
//%d打印的是有符号的十进制数:11111111(进行整型提升)
//有符号为负号:前补1:11111111111111111111111111111111(补码)
// 11111111111111111111111111111110(反码)
// 10000000000000000000000000000001(原码)符号位不变,按位取反)
//得到的最终结果仍然是-1;
signed char b = -1;//signed int 是有符号的char类型,与以上的结果一致;也为-1;
unsigned char c = -1;
//-1:的二进制位数:10000000000000000000000000000001原码
// 11111111111111111111111111111110反码
// 11111111111111111111111111111111补码
//11111111,此时因为是无符号类型,那么此时1代表的不是符号位,那么该数为正数,那么在前补0;
//00000000000000000000000011111111;正数的原码反码补码都是相同的,那么unsigned char c就为255;
printf("%d %d %d", a, b, c);
return 0;
}
-1:的二进制位数:10000000000000000000000000000001原码
11111111111111111111111111111110反码
11111111111111111111111111111111补码
%d打印的是有符号的十进制数:11111111(进行整型提升)有符号为负号:前补1:11111111111111111111111111111111(补码)
11111111111111111111111111111110(反码)
10000000000000000000000000000001(原码)符号位不变,按位取反)
得到的最终结果仍然是-1;
signed int 是有符号的char类型,与以上的结果一致;也为-1;
-1:的二进制位数:10000000000000000000000000000001原码
11111111111111111111111111111110反码
11111111111111111111111111111111补码
11111111,此时因为是无符号类型,那么此时1代表的不是符号位,那么该数为正数,那么在前补0;
00000000000000000000000011111111;正数的原码反码补码都是相同的,那么unsigned char c就为255;
2.
int main()
{
char a = 128;
//128的二进制位:00000000000000000000000010000000(正整数的原码反码补码相同)
//10000000:因为此时char为有符号类型,那么此时认为1是符号位,补1;
//11111111111111111111111110000000(补码)在计算机中存储的就是补码
//又因为此时%u,那么为无符号类型,此时为正数,那么原码反码补码均一致,结果就为以上;
printf("%u\n", a);//
return 0;
}
//128的二进制位:00000000000000000000000010000000(正整数的原码反码补码相同)
//10000000:因为此时char为有符号类型,那么此时认为1是符号位,补1;
//11111111111111111111111110000000(补码)在计算机中存储的就是补码
//又因为此时%u,那么为无符号类型,此时为正数,那么原码反码补码均一致,结果就为以上;
3.
int main()
{
char a = -128;//-128的二进制位数:10000000000000000000000010000000
// 11111111111111111111111101111111
// 11111111111111111111111110000000
//10000000:此时认为是有符号的char类型:补1:11111111111111111111111110000000
//又由于打印的是无符号数,那么结果为:原码反码补码都相同,那么结果同上!
printf("%u\n", a);
return 0;
}
4.
int main()
{
int i = -20;//10000000000000000000000000010100;
//11111111111111111111111111101011
//11111111111111111111111111101100//补码
unsigned int j = 10;//00000000000000000000000000001010;//原码补码反码相同
//11111111111111111111111111101100;
//11111111111111111111111111110110;//两个数的补码相加之后的结果
//11111111111111111111111111110101;减1
//10000000000000000000000000001010;原码 结果为-10;(符号位不变,进行取反)
printf("%d\n", i + j);
return 0;
}