数据的基本类型
c语言中,有着许多基本类型,而这些基本类型大部分都是内置类型,故名思意,就是在这个语言中最基本的类型;同时内置类型也是各个语言在设计初期所定义的类型。
常见的类型
char - 1Byte - 8bit - 字符类型
short - 2Byte - 16bit - 短整型
int - 4Byte - 32bit - 整形
long - 4Byte / 8Byte - 32bit / 64bit - 长整型
long long - 8Byte - 64bit - 更长整形
float - 4Byte - 32bit - 单精度浮点型
dauble - 8Byte - 64bit - 双精度浮点型
数据的基本类型归类
在c语言中,不同的类型有着不同的意义;不同的类型决定在内存中开辟空间的大小以及在内存中存储的方式,而在c语言中,我们也可以为这些类型进行归类。
整形类型
char
char
( C标准中对char是 Impementation Defined,就是未明确定义)
unsigned char
signed char
short
(signed) short
unsigned short
int
(signed) int
unsigned int
long
(signed) long
unsigned long
long long
(signed) long long
unsigned long long
浮点数类型
float
dauble
构造类型
数组类型
结构体类型 - struct
枚举类型 - enum
联合类型 - union
指针类型
int* pa; - 整形指针 - 指向整形的指针
char* pb; - 字符指针 - 指向字符的指针
float* pc; - 浮点型指针 - 指向浮点数的指针
void* pd; - 空指针 - 不指向任何类型的指针
空类型
void - 空类型(无类型) - 通常用于函数的返回类型,指针类型
数据在内存中的存储形式
在c语言中,任何数据都是存储在内存中的,但是不同类型数据存储的方式以及读取方式都大不相同。
整形的存储形式
在c语言中,数据的存储方式一般都是由二进制进行存储,而在一个整形数据的二进制中,有三种表达方式:
原码 反码 补码
原码
原码就是将一个整数转换为二进制的形式,就是其原码,当一个数据为一个有符号的数据时,其最高位为符号位。
例:
int a = 13; // - 0000 0000 0000 0000 0000 0000 0000 1101 int b = -15; // - 1000 0000 0000 0000 0000 0000 0000 1111
13 与 -15 的二进制位即为它们的原码
反码
负数的反码即为将原码符号位(首位)以外所有的二进制位 ( 数值位 ) 按位取反,也就是1变为0,0变为1。
以-15为例:
int b = -15; //1000 0000 0000 0000 0000 0000 0000 1111 - 原码 //1111 1111 1111 1111 1111 1111 1111 0000 - 反码
但是对于正数来说,它的原码反码补码都相同;
补码
负数的补码就是其反码再加上1,而在计算机内存中,存储整形类型数据时一般都为补码。
int b = -15; //1000 0000 0000 0000 0000 0000 0000 1111 - 原码 //1111 1111 1111 1111 1111 1111 1111 0000 - 反码 //1111 1111 1111 1111 1111 1111 1111 0001 - 补码
对于正数来说,它的原码反码补码都相同;
二进制位转为十六进制位时,每四位二进制位则表示一位十六进制位
则 -15 转换为十六进制位时则为"FF FF FF F1"
(从右往左读)
大小端
从上面的图可知,数据在内存中的存储不仅与原反补码有关,而且与某些因素也有关,在内存中存进去的十六进制位为"FF FF FF F1",但是在内存中显示的又是"F1 FF FF FF" 。该处就涉及到一个计算机的大小端问题。
大小端是一种表现形式,这种表现形式只出现在数据存储在内存中,而不是在寄存器中参与运算时的表现。
计算机在内存中存放数据的顺序都是从低地址到高地址,所不同的是首先取低字节的数据存放在低地址还是取高字节数据存放在低地址,这就是大小端的问题。
大端 - 把一个数据的低位字节,存放在高地址处;高位字节,存放在低地址处;
小端 - 把一个数据的低位字节,存放在低地址处;高位字节,存放在高地址处。
在c语言中,也可设计程序来判断机器的大小端。
#include<stdio.h> int check() { int n = 1;//创建变量n初始化为1 char* p = &n;//创建一个字符指针指向地址的前一个字节并返回 return *p; } int main() { if (check()) {//1在存储中若是小端则会存储在高地址处则为小端 printf("小端\n"); } else { printf("大端\n");//若是大端则会存储在低地址处 } return 0; }
浮点型在内存中的存储
浮点数是表示小数的一种方式,浮点数就是小数点的位置不固定,于此相反的由定点数,即小数点的位置固定。在内存中,整形数据是根据二进制的原码反码补码进行存储,而浮点数的存储方式又与整形数据的存储方式截然不同。
为了规定浮点数在内存中存储的方式,出现了一个国际标准 - IEEE(电气和电子工程协会) 754,在该标准中规定,任意一个二进制浮点数V都可被表示为下面的形式:
(-1)^S * M * 2^E
其中(-1)^S表示符号位,当S为0时,V为正数;当S为1时,V为负数。
M代表有效数字,且 2>M>=1。
2^E表示指数位。
以浮点数10.0与-10.0作为例子:
10.0 - 1010.0 - (-1)^0 * 1.01 * 2^3
S M E
-10.0 - -1010.0 - (-1)^1 * 1.01 * 2^3
IEEE 754中规定
对于32位的浮点数在内存中的存储形式为,最高1位为符号位S,接着的8位为指数E,剩下的23位为有效数字M。
对于64位的浮点数在内存中的存储形式为,最高1位为符号位S,接着的11位为指数E,剩下的52位为有效数字M。
V = (-1)^S * M *2^E
在规定中
S被正常保存,非0即1;(0代表V为正数,1代表V为负数)
M在内存中的保存形式为只保存有效数字小数点后面 . xxxxxx 部分,因为在一个小数中,利用科学计数法可以将任何非0的小数写为 1.xxxx * 2^E 的形式:
( -0.5 - -0.1 - 1.0 * 2^-2)
在浮点数的保存形式中
例:
1 1 1 1 . 1 1 1 1
权重 2^3 2^2 2^1 2^0 2^-1 2^-2 2^-3 2^-4
(故 -0.5 - -0.1)
又因能确保浮点数在内存中存储时能做到更高的精度,故M只保留有效数字 . xxxxxx 部分。
但也不是所有浮点数都能被完全没有误差的保存;
例如存入一个浮点数为4.4
小数点前的数可以利用0100来表示,但是小数点后的 .4 却不能没有误差的进行保存,根据权重算出,小数点后第一位为0.5,第二位为0.25,第三位为0.125......
E在内存中的保存形式,因为E为一个unsigned int类型的数值 - 即无符号整形
若是32位的浮点数,该范围为0 ~ 255
若是64位的浮点数,该范围为0 ~ 2047
而在浮点数用科学技术法的表现形式下,E难免出现负数,为了不在内存中出现存储错误,IEEE 754标准规定 E 在保存中应先加上一个中间值,即127或1023,在32位浮点数的情况下,加上127;64位浮点数的情况下,加上1023。
根据上述规定我们可知,如果存在2个变量
float ph = 10.5 ,pn = -0.5;
即10.5在内存的存储形式为
10.5 - 1010.1 - 1.0101 * 2^3 - V = (-1)^0 * 1.0101 * 2^3
S = 0(V为正数)
E = 3+127 = 130 - 1000 0010
M = 0101
即 0 10000010 01010000000000000000000
2进制每4位为一个16进制数
换为16进制即为 01000001001010000000000000000000 - 41 28 00 00
同样 -0.5在内存中的存储形式为
-0.5 - -0.1 - 1.0 * 2^-1 - V = (-1)^1 * 1.0 * 2^-1
S = 1(V为负数)
E = (-1)+127 = 126 - 0111 1110
M = 0
即1 01111110 00000000000000000000000
换为16进制即为10111111000000000000000000000000 - BF 00 00 00 00
浮点数从内存中的取出
在内存中,数据不仅需要存储,在使用时还需要取出,浮点数也是如此,在存储中,采用了IEEE 754的标准。
同样在取出数据的过程中IEEE 754也规定了相当的标准。
共分为3种情况
E不全0也不全1
规定当E不全0也不全1时,即指数 E 的十进制位减去127或1023得到真实值,有效数值M加上原有的1进行还原。
E全为0
当E全为0时,浮点数的指数E为1-127或者为1-1023即为真实值,此时M不再加上原有的1,而是还原为0.xxxxxx的形式。通常表示一个极为接近0的数值(其正负取决于符号位S)。
E全为1
这时的E若为全1的话,表示该数值在浮点数的范围种是一个±无限大的数值(其正负取决于符号位S)。