整数在内存中的存储
变量的创建需要在内存中开辟空间,空间的大小根据类型决定
计算机中的符号数有三种表示方法:原码、反码及补码
三种表示方法均有符号位和数值位两部分组成,符号位0表示正,1表示负
原码: 直接将数值按着正负数的形式翻译成二进制
反码: 将原码的符号位不变,其他位按位取反
补码: 反码+1
其中正数的原码反码补码均相同
对于整形来说,数据存放在内存中存放的是补码
原因:使用补码时,可以将符号位与数值位一同进行处理,加法和减法也可以一同处理(CPU中只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路
在计算机中存储数字的时候,是分为大小端进行存储的
那么什么是大小端?
大端存储模式
数据的低位存储在内存的高地址处,而数据的高位存放在内存的低地址处
小端存储模式
数据的低位存储在内存的低地址处,而数据的高位保存在内存的高地址处
为什么会有大小端?
在计算机系统中,以字节为单位,那么每个地址单元都对应着一个字节(8bit)但是在C语言中除了用8bit的char类型之外,还有16bit的short类型,32bit的long型(取决于编译器)另外对于位数大于8位的处理器(如16、32位的处理器)由于寄存器的宽度大于一个字节,那么必然存在将多字节安排的问题,由此就导致了有大端和小端存储模式
比如0x1122,那么0x11为高字节,0x22为低字节;那么对于大端存储,就将低字节的内容存放在内存的高地址处,0x11存放在低地址处
设计一个小程序来判断当前机器的字节序:
int main()
{
int a = 1;// a在内存中16进制表示形式:0x 00 00 00 01 字节序 01为低字节内容
char* p = (char *)&a;//取出第一个字节的地址内容(低地址) 查看是否为1
if (*p == 1)
{
printf("小端");
}
else
{
printf("大端");
}
return 0;
}
隐式类型转换
C的整形算术运算总是以缺省整形的精度来进行的。为了获取这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整形,这个过程被称为整形提升。
整形提升的意义: 表达式的整形运算要在CPU的相应运算器件中执行,CPU内运算器ALU的操作数长度一般就是int大小的字节长度,同时也是CPU通用寄存器的长度。因此,即使是两个char类型的相加,在CPU中执行时也是要先转换为CPU内整形操作数的标准长度。通用CPU是难以实现两个8比特字节直接相加运算,所以表达式中各种长度小于int长度的整形值,都必须先转换为int或者unsigned int类型,然后才能被送入CPU去执行运算。
整形提升:
如果是有符号类型,按着符号位进行整形提升,即高位补符号位
如果是无符号类型,高位补0
接下来来看几道例题
int main()
{
char a = 3;
//00000011
//首先字符型要转换为整形进行运算(整形提升),a是有符号数,所以高位补0
//00000000000000000000000000000011原码=补码
char b = 127;//2^7-1
//01111111 高位补0
//00000000000000000000000001111111原码=补码
//c = a + b
//00000000000000000000000010000010 此时运算结束,由于c是8bit的,所以发生整形截断
//10000010 此时为c在内存中的补码 之后转换为原码
//11111111111111111111111110000010 补码
//11111111111111111111111110000001 反码 = 补码 - 1
//10000000000000000000000001111110 原码 = -126
char c = a + b;
printf("%d\n", c);//-126
return 0;
}
int main()
{
char a = -1;//默认为有符号类型
//10000000000000000000000000000001 -1的原码
//11111111111111111111111111111110 反码
//11111111111111111111111111111111 补码
//发生截断
//11111111 %d按着有符号位进行打印
//发生整形提升 a是有符号的 又由于符号位为1 所以补1
//11111111111111111111111111111111 补码--算出原码进行打印
//11111111111111111111111111111110 反码
//10000000000000000000000000000001 原码 -1
signed char b = -1;//b与a一样都是有符号
unsigned char c = -1;
//整形提升 高位补0
//c对11111111(和上面计算相同)进行整形提升
//00000000000000000000000011111111 整数:补码=反码=原码
printf("a=%d b=%d c=%d", a, b, c);//-1 -1 255
return 0;
}
int main()
{
//整形提升 如果是有符号数 按着符号位进行提升 如果是无符号数就补0
char a = -128;
//10000000000000000000000010000000 -128的原码
//11111111111111111111111101111111 反码
//11111111111111111111111110000000 补码--内存中的数字
//由于char是一个字节 只有8bit 所以发生整形截断
//10000000 补码 整形提升提升符号位 发生整形提升 因为a是有符号的数
//11111111111111111111111110000000 补码这个数打印就是超大的数--无符号数 直接就是原码
printf("%u\n", a);//%u以无符号数打印整形 认为内存中存的是无符号数 原码反码补码是一个值
return 0;
}
int main()
{
//整形提升 如果是有符号数 按着符号位进行提升 如果是无符号数就补0
char a = -128;
//10000000000000000000000010000000 -128的原码
//11111111111111111111111101111111 反码
//11111111111111111111111110000000 补码--内存中的数字
//由于char是一个字节 只有8bit 所以发生整形截断
//10000000 补码 整形提升提升符号位 发生整形提升 因为a是有符号的数
//11111111111111111111111110000000 补码这个数打印就是超大的数--无符号数 直接就是原码
printf("%u\n", a);//%u以无符号数打印整形 认为内存中存的是无符号数 原码反码补码是一个值 所以结果为一个超大的数
return 0;
}
int main()
{
char a = 128;//-128~127意思是char容纳的值
//00000000000000000000000010000000 原码=反码=补码
//截断
//10000000 发生提升 a是有符号数 按着符号位进行提升
//11111111111111111111111110000000
printf("%u\n", a);//超大的数
return 0;
}
int main()
{
int i = -20;
//10000000000000000000000000010100 原码
//11111111111111111111111111101011 反码
//11111111111111111111111111101100 补码
unsigned int j = 10;
//00000000000000000000000000001010 原码=反码=补码
//补码相加
//11111111111111111111111111110110 i+j结果的补码
//11111111111111111111111111110101 反码
//10000000000000000000000000001010 原码-10
printf("%d\n", i + j);//-10
return 0;
}
int main()
{
unsigned int i;//无符号i不可能小于0
//死循环
//-1在内存中的补码:11111111111111111111111111111111--无符号数 所有位都是有效位就是超大的正数
for (i = 9; i >= 0; i--)//i >= 0 恒成立死循环
{
printf("%u\n", i);
}
return 0;
}
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
//数组中的数 -1 -2 -3 ... -128 127 126 ... 3 2 1 \0 总共256个 长度为255 因为不算\0
printf("%d", strlen(a));//255
return 0;
}
#include <stdio.h>
unsigned char i = 0;//无符号char范围:0~255
int main()
{
for (i = 0; i <= 255; i++)//255+1=0
{
printf("hello world\n");
}//死循环
return 0;
}