C语言类型
内置类型
整型家族
char //字符数据类型 1个字节
unsigned char
signed char
short//短整型 4个字节
unsigned short [int]
signed short [int]
int //整型 4个字节
unsigned int
signed int
long//长整型 8个字节
unsigned long [int]
signed long [int]
long long //更长整型 8个字节
浮点家族
float//单精度浮点数 4个字节
double//双精度浮点数8个字节
自定义类型(构造类型)
数组类型 arr[10]
结构体类型 struct
枚举类型 enum
联合类型 union
指针类型
int *i
char *c
float *fl
void * vo
空类型
void 通常用于函数的返回类型,void 指的是无返回值
类型的意义
1.使用这个类型开辟内存空间的大小
2.如何看待内存空间的视角。
比如我们使用int 我们认为开辟的这个空间就是来存整数的。如果使用float我们就认为这个空间是用来存储浮点数。
整型在内存中的存储
计算机中的有符号整数有三种表示方法,原码、反码、补码。
(无符号数 原码补码反码均相同,存储方式只有一种可以理解按照原码即为其二进制类型存储。)
三种表示方法均有符号位和数值位两部分组成,符号为是第一位,0代表正1代表负数 。数值位的表示方法则各不相同。
原码
直接将二进制按照正负数的形式存储
反码
符号为不变,其他位相较于原码依次取反
补码
在反码的基础上+1
举个例子
int a=10;
//00000000 00000000 00000000 00001010 原码
//00000000 00000000 00000000 00001010 补码
//00000000 00000000 00000000 00001010 反码
printf("%x\n",a);//十六进制 00 00 00 0a
int b=-10;
//10000000 00000000 00000000 00001010 原码
//11111111 11111111 11111111 11110101 补码
//11111111 11111111 11111111 11110110 补码
printf("%x\n",b);//ff ff ff f6
这个例子说明了整型在内存中存储是按照补码存储的。
原因是:使用补码,可以讲符号位和数值位统一处理,同时加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
计算机中减法其实并不是直接减而是加上一个被减数的负数
例如 1+1
在计算机中运算是1+(-1)来运算的,如果使用原码 大家可以自己算一下,是算不出来0这个结果的,但是使用补码就可以。
另外 实际内存中存储的时候分为大端存储和小端存储。
我们知道地址有低位和高位从左到右,那么整型所占据的32位第0位就是低位,第31位就是高位。
大端存储
数据字段的高位存储在地址的低位
例如 我们上述代码中的00 00 00 0a
第一个00是这个数据的高位 它存放在地址靠左也就是地址的低位我们称之为大端存储。
小端存储
数据字段的低位存储在地址的低位
例如 我们上述代码中的00 00 00 0a
在存储中存储的方式是 0a 00 00 00
第一个00是这个数据的高位 它存放在地址靠右也就是地址的高位我们称之为大端存储
我们可以写一段很简单的代码来判断自己的机器是大端还是小端存储
int main(){
int a=1;
char *p=(char *)&a;
if(*p==1){
printf("小端存储");
}else{
printf("大端存储");
}
return 0;
}
关于这个地方有个比较有意思的题:
int main(){
char a =-128;
printf("%u\n",a);
return 0;
}
猜想一下输出的答案是什么
答案是:4294967168
char a =-128;
10000000 00000000 00000000 10000000 原
11111111 11111111 11111111 01111111 反
11111111 11111111 11111111 10000000 补
因为是char类型 截出来最后八位
10000000
输出是%u无符号十进制
整型提升
本身是个负数提升的时候高位补充1
11111111 11111111 11111111 10000000 补
正常情况 十进制输出时要算出来它的反码和原码 但是这里是%u 这个补码就是原码
不需要再反向求出其反码和原码了 转换成十进制输出就可以了
浮点数在内存中的存储
先给出来一个例子
void float_EX1(){
/* 输出结果为:
* n的值位:9
* *pFloat的值位:0.000000
* n的值为:1091567616
* *pFloat的值为:9.000000
*/
int n=9;
float *pFloat= (float *)&n;
printf("n的值位:%d\n",n);
printf("*pFloat的值位:%f\n",*pFloat);
*pFloat=9.0;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
}
从这个例子我们首先可以得出结论:
整型存 只能用整型存储 不能用浮点型来取出来,浮点型存也只能用浮点型存储 不能用整型存
也就是说,整型在内存中存储与浮点型在内存中存储的方式是不同的。
根据IEEE 754 标准中定义
有符号零和非零的浮点型数都可以用
这个式子来表示。例如5.0 是 101.0 即(-1)^0 * 2^2* 1.01 对应 s=0,b为2 e为2 m为1.01 。
32位的单精度浮点数二十进制浮点数表示方式定义如下:
图1
图2
根据这个表可以得知
在32位下
1个bit位的符号位S
8个bit位的指数E
还有23个bit位的有效数字t
在64位下
1个bit位的符号位S
11个bit位的指数E
52个bit位的有效数字t
其他16或128请读者自行参考。
但是实际存储时,我们会发现所有的浮点型都能转换成1.****也就是说这个小数点前面的1是固定的。所以又可以省略一位只保留小数点后面这样有效为数字M就有多了一位,其精度就更高了
E的特殊情况
除此之外还有个关键的问题:
假设要存储0.5应该怎么存?
是这样:
0.5
转换成754种定义的是:
0.1 注意里0.1并不是十进制的0.1(小数点后面的值要用2的负数次幂表示 因为0.5是2^(-1) ,0.25就是2^(-2))
而是
2的-1次幂 2^(-1)就是0.5
转换成标准定义
(-1)^0 * 1.0 * 2^(-1)
所以实际情况中这个E有可能是负的
但是E中8个bit位并没有符号位那这里怎么办?
754中是这样的:让E=e(真实的幂值)+ bias(偏移量)
比如8个bit位我们让bias等于127 11个bit位的让bias等于1023
这样不管是多少最后都是一个正值
比如上面那个0.5的例子
S=0;
M=1.0;
e=-1
但真正的E=e+127=126
所以在真正存储的时候存的是126
那我们再写个例子验证一下
void float_EX2(){
float f =3.5;
int *pf=(int *)&f;
//3.5
//11.1
//(-1)^0 * 1.11 *2 ^ 1
//S=0
//M=1.11
//E=128 10000000
//0 10000000 11000000000000000000000 二进制
//0100 0000 0110 0000 0000 0000 0000 0000
//40600000 十六进制
printf("3.5在内存中存储的16进制是");
printf("%x\n",*pf);
//结果为 40b00000
//与计算结果一致
}
当然754中还规定了如果发现E为全0和E为全1的情况:
E为全零
E为全0代表的就是 2^(-127) 这样一个数字我们可以想一下2的32次方已经是个很大的数字了那么2的127次幂将会有多大,那如果将2的127次幂放入分母,这个数我们就认为它无限接近为零其实就是+- 无穷小了。
E为全1
与上面类似,E为全一 代表的是 2^128 即表示这个数字无穷大
最后我们再回顾上面给出的例子float_EX1()
void float_EX1(){
/* 输出结果为:
* n的值位:9
* *pFloat的值位:0.000000
* n的值为:1091567616
* *pFloat的值为:9.000000
*/
int n=9;
float *pFloat= (float *)&n;
printf("n的值位:%d\n",n);
printf("*pFloat的值位:%f\n",*pFloat);
*pFloat=9.0;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
}
整数 9
在内存中存储的补码是00000000 00000000 00000000 00001001
那么以浮点型指针访问并且以浮点型输出
就认为
符号为0 指数E00000000 有效位0000000 00000000 00001001
用754种定义的 标准格式
(-1)^0 * 0000000 00000000 00001001 * 2 ^(-126)
%f 只打印小数点后六位 所以输出的时候 是0.000000
然后再来分析
*pFloat=9.0;
这个时候需要以浮点型去存
1001.0
1.001 *2^3
(-1)^0 * 1.001 ^ 2^3
S=0
M=001
E=3+127=130
0 10000010 00100000000000000000000
我们对照其二进制
发现 0 10000010 00100000000000000000000 的值转化为10进制
就是1091567616
最后一个输出9.0 是因为我们以浮点数存以浮点数取出当然就还是9.0了
至此 数据存储就结束了,有问题欢迎讨论。
标签:11111111,存储,00000000,C语言,int,详解,printf,pFloat From: https://blog.51cto.com/u_16160587/6505731