C中浮点数据类型的结构(二进制格式)是啥?
Posted
技术标签:
【中文标题】C中浮点数据类型的结构(二进制格式)是啥?【英文标题】:What is the struct (binary format) of float datatype in C?C中浮点数据类型的结构(二进制格式)是什么? 【发布时间】:2020-06-01 13:21:38 【问题描述】:如何在 C 中找到有关 float
数据类型的信息?我的意思是这种类型的位结构(十进制,信号指示符等......)?
让我解释一下我要做什么:
我正在实现一个网络协议,我需要发送 6 个带有纬度和经度的八位字节(根据协议文档)。前 3 个八位字节必须有 LAT 信息,后 3 个必须有 LON 信息。
我不能在float
数据类型中使用按位运算符,所以为了调试,我将float
变量的内存复制到一个新的uint32_t
变量(均为4 字节宽),然后尝试移动位以获得正确的值,但它不起作用。
这是我用来测试/调试转换的代码:
int32_t b = 0;
memcpy(&b,&a,4);
int32_t c = (b >> 23);
printf("Valor de C: 0x%X, Decimal: %d\n",c,c);
// Should print only '23', but it's printing
// Valor de C: 0x41B, Decimal: 1051
在“知道”float 的正确位位置后,我会将这些位复制到我的协议数据中,该数据是一个 unsigned char[6] 数组(我无法更改类型,只能更改值)。
关于如何做到这一点的任何提示?
【问题讨论】:
你好。根据您粘贴的协议文档,数据不是存储为浮点数而是定点数。您可以在此处阅读有关定点数的信息:en.wikipedia.org/wiki/Q_(number_format)#Conversion。 您不需要为此使用float
类型的内部表示。你只需要价值。您使用的协议显然需要将角度(纬度或经度)编码为整数单位的二进制,其中单位为 180/2**23 度。因此,如果您在 float
中将角度表示为度数,请将其乘以 2**23/180 转换为多个单位,并将结果表示为二进制整数。
***.com/questions/385132
【参考方案1】:
这是一个示例代码,展示了如何对浮点纬度进行编码。 (经度也是一样)。 请参阅:https://en.wikipedia.org/wiki/Q_(number_format)#Float_to_Q,了解使用 2 个补码管理的定点编码。
它使用规范提供的权重的定点编码。
#include <stdio.h>
#include <stdlib.h>
int main()
/* weight of one bit */
const float weight = 180./(1 << 23);
printf ("w=%f\n",weight);
/* a few sample conversions */
/* 2.53 degres */
float lat = 2.53;
printf ("lat=%f\n",lat);
int fp_lat = (int) (0.5f + lat / weight);
printf ("fplat=0x%x\n",fp_lat);
lat = 180.f; /* +180 degres */
printf ("lat=%f\n",lat);
fp_lat = (int) (0.5f+ lat / weight);
printf ("fplat=0x%6x\n",fp_lat); /*exactly 23 bits */
/* negative numbers)*/
lat = -180.f; /* -180 degres */
printf ("lat=%f\n",lat);
fp_lat = (int) (0.5f + abs(lat) / weight);
if (lat <0)
/*2 complement representation */
fp_lat = (~fp_lat + 1) & 0xffffff;
printf ("fplat=0x%6x\n",fp_lat); /* same value as 180 */
/*sample packing for latitude */
unsigned char msg[6];
msg[0] = (unsigned char)((fp_lat >> 16) & 0xff); /* most significant byte of 24 bits*/
msg[1] = (unsigned char)((fp_lat >> 8 ) & 0xff);
msg[2] = (unsigned char)((fp_lat ) & 0xff);
/* to be continued */
return 0;
【讨论】:
【参考方案2】:数据的解释与数据是分开的。数据的单元与数据本身是分开的。所以我可以说123 milliseconds
或0.123 seconds
或234 half-milliseconds
或1.23 * 10^-2 seconds
所有这些形式表示相同的“值”。
你发布的数据我猜是由两个数字组成,编码为二进制补码,以大端表示,最高有效位在前。
unsigned char data[6]; // assuming indexes reference octet numbers
// big endian - first byte is the most significant
// I assume the hardware uses twos complement internally
// the method as described in https://***.com/questions/35876000/converting-24-bit-integer-2s-complement-to-32-bit-integer-in-c
int32_t latitude_value = (int32_t)( data[0] << 24 | data[1] << 16 | data[2] << 8 ) / 256;
// latitude_value represents latitude in units of 180/2^23 degrees
现在,如果您想以这种方式表示它,您可以将 latitute 从 180/2^23 degrees
的单位“转换”为普通的 degrees
单位:
double latitue_in_degrees = (double)latitude * 180.0 / exp2(23);
注意there are problems with floating point types。
C 中 float 数据类型的结构(二进制格式)是什么? 如何在 C 中找到有关 float 数据类型的信息? 我的意思是这种类型的位结构(十进制、信号指示符等)?
float
类型的确切格式取决于您的编译器 - 它可以是任何东西。那么,绝大多数今天的系统/编译器使用 binary32
格式,来自 IEC 754 标准的 float
数据类型。有关数据类型的确切格式,请参阅标准和无尽的网络资源。例如this converter is just fun to use。
【讨论】:
您好,您从定点到浮点的转换仅在未设置第 24 位时有效。否则需要反转2个补码(负数) 哦,你完全正确!我想我可以data[0]<<24
然后/ 256
。【参考方案3】:
通常为此目的使用位字段。你可以试试这样的:
#pragma pack(1)
typedef struct
union latitude
uint32_t value : 24;
struct octets
uint8_t octetOne : 8;
uint8_t octetTwo : 8;
uint8_t octetThree : 8;
union longitude
uint32_t value : 24;
struct octets
uint8_t octetOne : 8;
uint8_t octetTwo : 8;
uint8_t octetThree : 8;
frame;
然后将传入数据存储在此结构中并通过以下方式访问所需的值:
frame.longitude.value
等
【讨论】:
如果结构声明中没有强制填充,映射可能不起作用。#pragma pack(1)
是微软特定的编译指示。 Usually for such purposes bit fields are used
的代码针对一个特定的编译器和体系结构,它支持以特定的方式将字段打包到存储单元中。遗憾的是,位域在机器和编译器之间不可移植,位掩码是首选。
您的建议假设在运行代码的机器上,value
的 msb 将具有内存中的最低地址。这不是你总能期待的(字节序问题)以上是关于C中浮点数据类型的结构(二进制格式)是啥?的主要内容,如果未能解决你的问题,请参考以下文章