C语言进阶|C语言进阶——数据在内存中的存储

目录
一、数据类型基本归类
1、整型家族
2、浮点数家族
3、构造类型(自定义类型)
4、指针类型
5、空类型
二、整型在内存中的存储:原码、反码、补码
三、大小端字节序介绍及判断
四、浮点型在内存中的存储
1、二进制浮点数表示形式
2、有效数字M和指数E的特别规定
(1)有效数字M
(2)指数E
五、练习
一、数据类型基本归类 之前我们已经学习了基本的内置类型:

char//字符型
short//短整型
int//整型
long//长整型
long long//更长的整型
float//单精度浮点数
double//双精度浮点数
1、整型家族
char
unsigned char
signed char
short
unsigned short
signed short
int
unsigned int
signed int
【C语言进阶|C语言进阶——数据在内存中的存储】long
unsigned long
signed long
2、浮点数家族
float
double
3、构造类型(自定义类型)
数组类型
结构体类型 struct
枚举类型 enum
联合类型 union
4、指针类型
int* pi;
char* pc;
float* pf;
void* pv;
5、空类型
void表示空类型(无类型),通常用于函数的返回类型、函数的参数、指针类型。
二、整型在内存中的存储:原码、反码、补码 计算机中的有符号数有三种表示方法:原码、反码、补码。
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位三种表示方法各不相同。
●原码:直接将二进制按照正负数的形式翻译成二进制就可以。
●反码:将原码的符号位不变,其他位依次按位取反就可以得到了。
●补码:反码+1
●正数的原、反、补码都相同。
●对于整数来说,数据存放内存中其实存放的是补码。
三、大小端字节序介绍及判断
●大端模式:
指数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中。
●小端模式:
指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
例:请设计一个小程序来判断当前机器的字节序。
int main() { int a=1; char* p=(char*)&a; if(*p==1) printf("小端!\n"); else printf("大端!\n"); return 0; }

四、浮点型在内存中的存储 1、二进制浮点数表示形式
IEEE 754规定任意一个二进制浮点数可以表示成下面的形式:
●(-1)^S*M*2^E
●(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数
●M表示有效数字,大于等于1,小于2
●2^E表示指数位
●对于32位浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
例:
十进制的5.0,二进制为101.0,相当于1.01*2^2。则s=0,M=1.01,E=2。
十进制的-5.0,二进制为-101.0,相当于-1.01*2^2。则s=1,M=1.01,E=2。
2、有效数字M和指数E的特别规定 (1)有效数字M
M写成1.xxxxxxx的形式。
在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxxx部分。
如:保存1.01时,只保存01,等待读取时,再把第一位的1加上去。这样可以节省1位有效数字。
(2)指数E
E为一个无符号整数(unsigned int)。
如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。
因此,IEEE 754规定,存入内存时E的真实值必须再加上一个中间数。
如果E为8位,中间数为127;如果E为11位,中间数为1023。
如:2^10的E是10,所以保存成32位浮点数,必须保存成10+127,即10001001。
E从内存中取出来还可以再分成三种情况:
●E不全为0或不全为1
指数E的计算值减去127(或1023)得到真实值,再将有效数字M前加上第一位的1。
如:0.5的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,即1.0*2^(-1),其阶码为-1+127=126,表示为01111110,而尾数1.0去掉整数部分为0,补齐0到23位,则其二进制表示形式为:
0 01111110 00000000000000000000000
●E全为0
E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
●E全为1
如果有效数字M全为0,表示±无穷大(正负取决于符号位s)
例:
int main() { int n=9; float* pFloat=(float*)&n; printf("n的值为:%d\n",n); //9 printf("*pFloat的值为:%f\n",*pFloat); //0.000000 //n此时为整型,在内存中为00000000000000000000000000001001 //被作为浮点数时,0 00000000 00000000000000000001001,即+0.00000000000000000001001*2^(-126)*pFloat=9.0; printf("num的值为:%d\n",n); //1091567616 printf("*pFloat的值为:%f\n",*pFloat); //9.000000 //n此时为浮点数,在内存中为0 00000000 00000000000000000001001 //被作为整型时,00000000000000000000000000001001 return 0; }

五、练习 例1:输出什么?
#include int main() { char a=-1; //11111111,认为第一位为符号位 signed char b=-1; //11111111,认为第一位为符号位 unsigned char c=-1; //11111111,unsigned不认为第一位为符号位,认为补码就是原码 printf("a=%d,b=%d,c=%d",a,b,c); //输出a=-1,b=-1,c=255 return 0; }

例2:输出什么?
//1 #include int main() { char a=-128; printf("%u\n",a); //输出4294967168,%d才正确 return 0; } //2 #include int main() { char a=128; printf("%u\n",a); //也输出4294967168,%d才正确 return 0; }

例3:输出什么?
int main() { int i=-20; unsigned int j=10; printf("%d\n",i+j); //输出-10 return 0; }

例4:输出什么?
int main() { unsigned int i; for(i=9; i>=0; i--)//无符号类型恒大于等于0,因此恒成立 { printf("%u\n",i); //死循环 } return 0; }

例5:输出什么?
int main() { char a[1000]; int i; for(i=0; i<1000; i++) { a[i]=-1-i; } //-1 -2 -3 ... -127 -128 127 126 ... 3 2 1 0 -1 -2 ... -127 -128 127... printf("%d",strlen(a)); return 0; }

例6:输出什么?
unsigned char i=0; int main() { for(i=0; i<=255; i++)//死循环,因为i一直小于等于255 { printf("hellp world\n"); } return 0; }


    推荐阅读