我有一个要求,我需要读取单精度IEEE754浮点数表示形式的4个原始字节,以便按原样在串行端口上进行发送。我只是想问一下以下提取字节的正确方法是什么?
1。)创建一个联合,例如:
typedef union {
float f;
uint8_t bytes[4];
struct {
uint32_t mantissa : 23;
uint32_t exponent : 8;
uint32_t sign : 1;
};
} FloatingPointIEEE754_t ;
,然后在写入浮点变量bytes[]
之后只读取f
数组吗?
2。)或者,通过使uint32_t
类型的指针指向float
变量的函数来提取字节,然后通过屏蔽来提取字节
uint32_t extractBitsFloat(float numToExtFrom, uint8_t numOfBits, uint8_t bitPosStartLSB){
uint32_t *p = &numToExtFrom;
/* validate the inputs */
if ((numOfBits > 32) || (bitPosStartLSB > 31)) return NULL;
/* build the mask */
uint32_t mask = ((1 << numOfBits) - 1) << bitPosStartLSB;
return ((*p & mask) >> bitPosStartLSB);
}
进行呼叫的方式如下:
valF = -4.235;
byte0 = extractBitsFloat(valF, 8, 0);
byte1 = extractBitsFloat(valF, 8, 8);
byte2 = extractBitsFloat(valF, 8, 16);
byte3 = extractBitsFloat(valF, 8, 24);
如果您认为上述两种方法都错了,请给我建议正确的方法!
答案 0 :(得分:3)
首先,我假设您专门针对float
实际上是在IEEE754 单中表示的{strong> 的平台进行编码。一般来说,您不能将其视为理所当然的,因此您的代码无法移植到所有平台。
然后,union
方法是正确的方法。但是不要添加该位域成员!无法保证位的排列方式,因此您可能会访问错误的位。只需这样做:
typedef union {
float f;
uint8_t bytes[4];
} FloatingPointIEEE754;
此外,请勿在您自己的类型中添加后缀_t
。在POSIX系统上,这是为实现保留的,因此最好始终避免这种情况。
除了使用union
,还可以通过char
指针访问字节:
unsigned char *rep = (unsigned char *)&f;
// access rep[0] to rep[3]
请注意,在两种情况下,您都在访问内存中的表示形式,这意味着您必须注意计算机的endianness。
您的第二个选项不正确,它违反了 strict别名规则。简而言之,不允许您通过不具有兼容类型的指针访问对象,char
指针是访问表示形式的显式异常。确切的规则写在{11},这是C11标准的最新草案。
答案 1 :(得分:2)
您可以这样做:
unsigned char *p = (unsigned char *)&the_float;
,然后从p
指向的位置读取4个字节(例如p[0]
,p[1]
等)。最佳的“读取4个字节”代码取决于串行端口函数以何种形式接收数据。
答案 2 :(得分:1)
如果您不关心字节序,只需为指向浮点地址的字符指针添加别名。该标准明确允许使用字符指针来访问任何类型的表示形式的字节。如果您需要特定的字节序来在串行端口上发送字节,则可以在发送之前进行测试:
简单方法,只需使用本地字节序:
float f;
...
char * bytes = &f; // bytes point the the beginning of a char array of size sizeof(f)
自动测试字节序,并使用大字节序(AKA网络顺序)。 struct
只是一个返回数组并具有线程安全代码的技巧。
struct float_bytes {
char bytes[sizeof(float)];
};
struct float_bytes(float f) {
float end = 1.;
float_bytes resul;
char *src = (char *) &f;
if (*end == 0) { // end is 0 on a little endian platform, else 0x3f
int i = sizeof(f) { // little endian: reverse the bytes
while (i > 0) {
resul.bytes[--i] = src++;
}
}
else { // already in big endian order, just memcpy
memcpy(&(resul.bytes), &f, sizeof(f));
}
return resul;
}
当心:仅当浮点为IEEE754单点时,字节序测试才有意义。