一、数据类型
什么是数据类型:C语言中,为了方便编译器或者解释器程序员如何使用数据,根据数据的需要的空间大小对所有数据进行了分类。
二、类型的基本归类
在学习C语言初期,我们就会接触到如下基本的数据类型,了解了它们的用法和空间大小
char //字符型数据类型(1bit)
short //短整型(2bit)
int //整型(4bit)
long //长整型(4bit)
long long //长长整型(8bit)
float //单精度浮点型(4bit)
double //双精度浮点型(4bit)
这里我们详细的介绍C语言各数据类型
1. 整型
char //char有无符号是不确定的,需要具体根据编译器来看
unsigned char //无符号的字符型
signed char //有符号的字符型,一般默认有符号。
short
unsigned short [int]//int可以省略。
signed short [int]
int
unsigned int
signed int
long
unsigned long
signed long
2. 浮点型
float
double
long double
3. 构造类型(自定义类型)
数组类型 | 根据需要的数据类型选择相应的关键词 |
结构体类型 | struct |
枚举类型 | enum |
联合类型 | union |
4. 指针类型
int* pi;
char* pc;
float* pf
void* pv
5. 空类型
void 表示空类型(无类型)
通常应用于函数的返回类型,函数的参数,指针类型。
三、整型在内存中的存储
1. 原码、反码、补码
计算机中的整数有三种二进制表示方法,即原码、反码和补码。
三种表示方法俊有符号位和数值位两部分组成,符号位是指整型数组转化为二进制后,左边第一位数字,其中“0”表示“正”,“1”表示“负”。而数值位,根据整型数据正负不同,三种表示方法也有差异。
- 正整数的原码、反码、补码是相同的,即直接换算为二进制后的数据;
- 负整数的原码是之间按照正负数的形式翻译成二进制数据;
- 负整数反码是在原码的基础上,除了符号位,其他位数按位取反;
- 负整数的补码是在原码的基础之上加1即可;
比如:
int a = 5;//(32bit)转换位二进制是:101
//00000000000000000000000000000101(原码)
//00000000000000000000000000000101(反码)
//00000000000000000000000000000101(补码)
//第一个“0”表示正负符号位
//0为正、1为负
int b = -5;
//10000000000000000000000000000101(原码)
//11111111111111111111111111111010(反码)
//11111111111111111111111111111011(补码)
//负数的原码的符号位不变,其他位按位取反得到对应的反码。
//反码+1就是补码。
对于整数来说,内存中存放的是数据的补码,打印出来的是原码的值。原因是因为CPU中只有加法,要实现减法需要加符号如:1+(-1)。使用补码,可以将符号位和数值域统一处理。同时加法和减法也可以统一处理,此外,原码和补码相互转换,其运行过程是相同的,不需要额外的硬件电路。
2. 大小端介绍
2.1 什么是大小端
大小端字节序存储包括(概念):
大端字节序存储:把一个数据低位字节处数据存放在高地址处,把高位字节处的数据存放在低地址处。如:
低< 11 22 33 44 >高
小端字节序存储:把一个数据高位字节处数据存放在高地址处,把低位字节处的数据存放在低地址处。如:
低< 44 33 22 11 >高
2.2 为什么会有大小端
在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节8个bit,对于位数大与8位的处理器,由于寄存宽度大于一个字节,那么必然存在着如何将多个字节安排的问题,因此导致了大端和小端存储模式。
我们可以通过一段代码来判断数据存储是大端还是小端
//通过判断该数据地址的第一个字节来确定大小端存储。
int check_sys()
{
int a = 1;
return *(char*)&a;
}
int check_sys(char* p)
{
int a = 1;
}
int main()
{
int a = 1;
char* pa = &a;//int ret = check_sys();
if(*p == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
//00000000000000000000000000000001
//00 00 00 01,或01 00 00 00
return 0;
}
四、浮点数在内存中的存储
1. 常见的浮点数
- 3.141
- 1E10
浮点数家族包括:float;double;long double等。
2. 浮点数存储规则
根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数V可以表示成以下形式:
(-1)^S*M*2^E
//(-1)^S表示符号位,当S=0,V为正数,当S=1,V为负数。
//M表示有效数字,大于等于1,小于2。
//2^E表示指数位。
举例来说:
十进制的5.0,写成二进制形式是101.0,相当于1.01×2^2。那么,按照以上规则,可以得到
S=0,M=1.01,E=2。((-1)^0*1.01×2^2)
十进制的-5.0,写成二进制是-101.0,相当于-1.01×2^2。那么
S=1,M=1.01,E=2。
浮点数存在有精度误差,原因是二进制保存浮点数时,对小数点表示可能存在总差一点的情况,导致二进制长度很长,因此要表示一些浮点数,只能通过四舍五入来表示。
IEEE规定:对于32位的浮点数,最高位的1表示符号位S,接着的8位是指数E,剩下的23位为有效数字M。
对于64位的浮点数,最高位的1表示符号位S,接着的11位是指数E,剩下的52位为有效数字M。
IEEE 754规定:有效数字M,M的取值为[1,2),也就是说,m可以写成1.xxxxx。同时,计算机在内部保存时,默认m的值最开头总为‘1’,因此1可以被舍去,只保存后面的小数部分。读取时再加上去,以增大浮点数的取值范围。
对于指数E,E是一个无符号数,这意味着如果E为8位,其取值范围为0~255,E为11位时,其取值范围为0~2047。但系统中的存储位置默认开头第一位是符号位,即默认数值有负数,与E本身发生冲突,因此在存储时,会在E原来的值上再添加一个数,对于8位的E,会在原来基础上加127;
对于11位的E,会在原来基础上加1023。如下:
int main()
{
float f = 5.5;
//二进制形式为101.1
//根据浮点数存储规则表示为(-1)^0*1.001*2^2
//S = 0
//E = 2 + 127 = 129
//M = 1.011
//存储到内存中为:010000001011000000000000000000000
return 0;
}
3. 浮点数的读取
浮点数的读取是按存储的规则逆序拿出。
分为以下三种情况:
- E不全为0或不全为1:这时浮点数指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位“1”。
- E全0时:这时浮点数的指数E等于1-127(或1-1023)即为真实值。有效数字M不再加上第一位数字“1”,而是还原为0.xxxxxx的小数,这样做是为了表示+-0,以及接近于0的很小的数字。
- E全为1时:这时,如果有效数字M全为0时,表示±无穷大的数字。(正负取决于S的符号位)
以上就是C语言中数据的存储的相关知识啦,如果有什么疑问或者哪里有错误,可以在评论区提出来,我是半路出家的C语言小白,请大家多多指教。