目录
前言
最近在一个项目协议中遇到了一个问题,就是数据类型问题,
主要有一些之前没见过的类型在计算机占位大小,及在串口获取后从数组buf转换float类型问题,在这里就将C语言常见的数据类型都记录下;
要想弄清楚buf转换位float数正确,就得先了解清除float在计算机中的存储格式逻辑。
本篇文章主要介绍常见c语言在计算机占位大小,数组转换float类型问题;
1、C语言一些类型介绍
1.1、基本类型所占字节大小
类型 | 16编译器 | 32编译器 | 64编译器 |
---|---|---|---|
char | 1 | 1 | 1 |
long | 4 | 4 | 8 |
shor | 2 | 2 | 2 |
float | 4 | 4 | 4 |
double | 8 | 8 | 8 |
int | 2 | 4 | 4 |
short int | 2 | 2 | 2 |
long long | 8 | 8 | 8 |
real4 | 4 | 4 | 4 |
real8 | 8 | 8 | 8 |
指针 * | 2 | 4 | 8 |
1.2、real、integet类型
1.2.1、 real 和 float 数据类型 的区别
real 有real4、real8、real10等类型
类型 | 主体 | 存储数据不同 | 表示范围不同 |
---|---|---|---|
float | 浮点型数据类型 | 数据类型用于存储单精度浮点数或双精度浮点数 | -3.4E+38 ~ 3.4E+38 |
real4 | 数据类型用于存储单精度浮点数 | 数据类型保存单精度浮点数。它是一种近似数字数据类型,在算术运算后容易产生舍入误差。 | -3.402823e+38 到 3.402823e+38,最趋近于零的数为 1.175494351e-38 |
储存方式
类型 | 符号位 | 指数 | 位数 | 指数偏移 |
---|---|---|---|---|
float(32位) | 1位符号位(s) | 8位指数(e) | 23位尾数(m,共32位) | 127(7FH) |
double | 1位符号位(s) | 11位指数(e) | 52位尾数(m,共64位) | 1023(3FFH) |
real*4 | 1位符号位(s) | 8位指数(e) | 23位尾数(m,共32位) | 127(7FH) |
real*8 | 1位符号位(s) | 11位指数(e) | 52位尾数(m,共64位) | 1023(3FFH) |
real*10 | 1位符号位(s) | 15位指数(e) | 64位尾数(m,共80位) | 16383(3FFFH) |
1.2.2、integer和int的区别
Integer是java为int提供的封装类。Integer 是一个类,是int的扩展,定义了很多的转换方法。本人属于C语言阵营,对JAVA不了解就不多描述,我在做项目时直接看作int类型>o< 。
1、Integer是Int的包装类,Int是八种基本数据类型之一。
2、Integer变量必须实例化以后才可以使用,而Int变量不需要实例化。
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象,而Int是直接存储数据值。
4、Integer的默认值是null,Int的默认值是0。
2、float 类型在计算机中储存逻辑
其中float的存储方式如下图所示:
而双精度的存储方式为:
2.1、float存储举例
将123.625数据在计算机内存中存储是怎样的格式呢
1、首先将123.625转换为假定的二进制
123 二进制 111 1011
0.625 二进制 101
那么123.625二进制为 111 1011.101
2、将111 1011.101的小数点左移,直到小数点前面只剩一位1
移动了6位,那么可以理解为 1.1 1101 1101*2^6
底数:因为小数点前必为1,所以IEEE规定只记录小数点后的就好。所以,此处的底数为:1 1101 1101
指数:实际为6,必须加上127,所以为133。也就是1000 0101
符号:整数,所以是0
最终 123.625在内存中储存的格式是
0 1000 0101 111 0111 0100 0000 0000 0000
2.1.1、在线float、double数转换链接
https://tooltt.com/floatconverter/
2.2、将计算机中的float类型数读取出来十进制表示
例如:将存储的一个float数输出出来,有了上面的存逻辑,读取的话就方便多了
这里用键盘输入计算机存储的二进制来模拟实现
例:01000010110010001000000000000000 (该数为:100.25)
S符号位(0表示正数,1表示负数) | E指数 | m尾数 | e指数偏移 |
---|---|---|---|
0 | 10000101 | 10010001000000000000000 | 127 |
符号位: S=0
指数偏移: e=127
指数: E=(10000101)2 = 133
E-e=133-127=6
尾数: m=(10010001000000000000000)2将后面的0去掉 再在前面补上必为1的整数值1.10010001
V= (1.10010001)2*2^6= (1100100.01)2
整数 :(1100100)2=100 小数:(0.01)2=0.25
//计算公式
//当E(各位)为全'0'时
//在real*4时:
V = (-1)^S*2^(-126)*m;
//在real8时:
V = (-1)^S*2^(-1022)*m;
//当E(各位)不为全'0'且不为全'1'时
V = (-1)^S*2^(E-e)*(m+1);
V=(-1)^0 2^(133-127)(0.10010001+1);
注意:
1、这里的(0.10010001)2指的是二进制方式,不是十进制0.10010001的值
2、*2^6并不是去乘以64,因为这里是二进制所以这里可以理解为小数点向后移6位
3、将四字节转换为float数
原理逻辑:
将这四个字节转换成一个32位无符号的数值,将该数值的地址指针强制转换为float指针类型(float*),在取出它的值*(float*)
//四个字节转换为一个float数
float Byte_to_Float(uint8_t *p)
{
float float_data=0.0;
unsigned long longdata = 0;
longdata = (*p<< 24) + (*(p+1) << 16) + (*(p + 2) << 8) + (*(p + 3) << 0);
float_data = *(float*)&longdata;
return float_data;
}
4、将float数用四字节表示
原理逻辑:
当计算机读取一个float数时,计算机会找到这个数的地址然后以存储的指针类型(float格式)一次性读取四个字节,并以float格式转换为十进制的值
而当计算机要读取一个字符时,这时他是一次性读取一个字节;
所以要将float转为char时是需要连续读取四次即可。
//浮点数转换为四字节
void FloatToByte(float floatNum,uint8_t* byteArry)
{
char* pchar=(char*)&floatNum;
for(int i=0;i<4;i++)
{
*byteArry=*pchar;
pchar++;
byteArry++;
}
}
时间:20230705