知识的价值不在于占有,而在于使用。这篇文章主要讲述C语言进阶——数据的存储相关的知识,希望能为你提供帮助。
数据的存储深度剖析数据在内存中的存储
- 数据类型详细介绍
- 整型在内存中的存储:原码、反码、补码
- 大小端字节序介绍及判断
- 浮点型在内存中的存储解析
- C语言类型
- 类型的意义
- 类型的基本归类
原码、反码、补码
int main()
{
int a=20;
//二进制
//0000 0000 0000 0000 0000 0000 0001 0100 原码
//0000 0000 0000 0000 0000 0000 0001 0100 反码
//0000 0000 0000 0000 0000 0000 0001 0100 补码
//十六进制
//0x00 00 00 14int b=-10;
//1000 0000 0000 0000 0000 0000 0000 1010 原码
//1111 1111 1111 1111 1111 1111 1111 0101 反码
//1111 1111 1111 1111 1111 1111 1111 0110 补码
//补码的十六进制
//0xFF FF FF F6//整数在内存中是倒着存的
//例如:
//a的存储:0x14 00 00 00
//b的存储:0xF6 FF FF FFreturn 0 ;
}
梳理
在实际代码运行中,数据并不是按照我们写的数值顺序存储。为什么呢?
大小端介绍1.什么是大端小端
2.为什么有大端和小端:
百度2015年系统工程师笔试题
//小程序
int check_sys(void)
{
int a=1;
char* p=(char*)&
a;
if(*p==1)
{
return 1;
}
else
{
return 0;
}
}//优化1
int check_sys(void)
{
int a=1;
char* p=(char*)&
a;
//返回1,小端
//返回0,大端
return *p;
}//优化2
int check_sys(void)
{
int a=1;
return *(char*)&
a;
}//指针类型的意义:
//1.指针类型决定了指针解引用操作符能访问几个字节:char*p;*p访问了一个字节,int*p;*p访问4个字节
//2.指针类型决定了指针+1,-1,加的或减的是几个字节;char*p;p+1,跳过一个字节,int*p;p+1,跳过4个字节int main()
{
//写一段代码告诉我们当前机器的字节序
//返回1,小端
//返回0,大端
int ret = check_sys();
if(ret==1)
{
printf("小端\\n");
}
else
{
printf("大端\\n");
}return 0 ;
}
练习1
//练习1
//输出什么?
#include <
stdio.h>
int main()
{
char a=-1;
//1000 0000 0000 0000 0000 0000 0000 0001
//1111 1111 1111 1111 1111 1111 1111 1110
//1111 1111 1111 1111 1111 1111 1111 1111
//1111 1111 char类型只能存储1个字节-8个bitsigned char b=-1;
//1000 0000 0000 0000 0000 0000 0000 0001
//1111 1111 1111 1111 1111 1111 1111 1110
//1111 1111 1111 1111 1111 1111 1111 1111
//11 11 11 11unsigned char c=-1;
//0000 0000 0000 0000 0000 0000 1111 1111
//255printf("a=%d,b=%d,c=%d",a,b,c);
return 0 ;
}//输出:a=-1,b=-1,c=255
练习2
//练习2
//输出什么
int main()
{
char a=-128;
//1000 0000 0000 0000 0000 0000 1000 0000 原码
//1111 1111 1111 1111 1111 1111 0111 1111 反码
//1111 1111 1111 1111 1111 1111 1000 0000 补码
//1000 0000
//1111 1111 1111 1111 1111 1111 1111 1111 整型提升(整型提升按照符号位提升)printf("%u\\n",a);
return 0;
}
有符号的char的范围是:-128~127
无符号的char的范围是:0~255
练习3
//按照补码的形式进行运算,最后格式化成为有符号整数
int main()
{
int i=-20;
//1000 0000 0000 0000 0000 0000 0001 0100 原码
//1111 1111 1111 1111 1111 1111 1110 1011 反码
//1111 1111 1111 1111 1111 1111 1110 1100 补码unsigned int j=10;
//0000 0000 0000 0000 0000 0000 0000 1010 补码//补码相加
//1111 1111 1111 1111 1111 1111 1110 1100 补码
//0000 0000 0000 0000 0000 0000 0000 1010 补码
//1111 1111 1111 1111 1111 1111 1111 0110 结果
//1111 1111 1111 1111 1111 1111 1111 0101 结果的反码
//1000 0000 0000 0000 0000 0000 0000 1010 结果的原码
//-10 结果的十进数printf("%d\\n",i+j);
//-10return 0 ;
}//输出:-10
练习4
int main()
{
unsigned int i;
//当i为无符号数时,减到0的时候再往下减的数还是整数,会把符号位的负数标志1加进去,始终是正数
//可是当i减到负数,是一个很大的数时,i!=9,怎么进入循环?
for(i=9;
i>
=0;
i++)
{
printf("%u\\n",i);
}return 0 ;
}//结果:无限循环
练习5
int main()
{
char a[1000];
//char的范围:-128~127
int i;
for(i=0;
i<
1000;
i++)
{
a[i]=-1-i;
//-1~128 127~0
}
printf("%d",strlen(a));
//255return 0 ;
}//输出:255
练习6
unsigned char i=0;
int main()
{
for(i=0;
i<
=255;
i++)//255+1=0
{
printf("hello world\\n");
}return 0 ;
}//结果:无限打印hello world
浮点型在内存中的存储解析常见的浮点数:
浮点数存储的例子:
int main()
{
int n=9;
float *pFloat=(float *)&
n;
printf("n的值为:%d\\n",n);
//9
printf("*pFloat的值为:%d\\n",*pFloat);
//0.000000*pFloat=9.0;
printf("num的值为:%d\\n",n);
//1091567616
printf("*pFloat的值为:%f\\n",*pFloat);
//9.000000return 0 ;
}//输出:
//9
//0.000000
//1091567616
//9.000000//总结:整型和浮点数存储不同
浮点数的存储的详细解读
【C语言进阶——数据的存储】根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数V可以表示成下面的形式:
IEEE 754规定:
- 对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M
- 对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位位有效数字M
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。
至于指数E,情况就比较复杂。
首先,E为一个无符号整数( unsigned int )这意味着,如果E为8位,它的取值范围为0~255; 如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数127/1023,对于8位的E,这个中间数是127; 对于11位的E,这个中间数是1023。比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。
int main()
{
float f = 5.5;
//5.5
//101.1
//(-1)^0 * 1.011 * 2^2
//S = 0
//M = 1.011
//E = 2 (E=2+127=129)
//S(1bit)E(8bit)M(23bit)
//010000001 011 0000 0000 0000 0000 0000
//0100 0000 1011 0000 0000 0000 0000 0000
//4 0 B 0 0 0 0 0return 0;
}
然后,指数E从内存中取出还可以再分成三种情况∶
E不全为0或不全为1
E全为0
E全为1
int main()
{
int n=9;
//0000 0000 0000 0000 0000 0000 0000 1001 原码/补码float *pFloat=(float *)&
n;
printf("n的值为:%d\\n",n);
//9printf("*pFloat的值为:%f\\n",*pFloat);
//0.000000
//0000 0000 0000 0000 0000 0000 0000 1001
//0.000 0000 0000 0000 0000 1001
//(-1)^0 * 0.000 0000 0000 0000 0000 1001 * 2^-126
//结果无限接近于0,且只打印小数点后6位*pFloat=9.0;
//1001.0
//1.001 * 2^3
//(-10)^0 * 1.001 *2^3
//0 10000010 001 0000 0000 0000 0000 0000
//printf("num的值为:%d\\n",n);
//1091567616
//1001.0
//1.001 * 2^3
//(-10)^0 * 1.001 *2^3
//0 10000010 001 0000 0000 0000 0000 0000
//1091567616printf("*pFloat的值为:%f\\n",*pFloat);
//9.000000return 0 ;
}
推荐阅读
- Spring功能介绍加载时织入机制的Aspectj和LoadTimeWeaving技术
- u盘安装win7系统详细图文详细教程图解
- 装机高手教你怎样用u盘安装win7系统
- U打开u盘制作工具最新推荐
- 装机高手教你处理mmc无法创建管理单元
- 装机高手教你bios设置硬盘模式
- 装机高手教你进入bios
- fast无线网卡驱动安装图文详细教程
- 装机高手教你打开360u盘小助手