我需要从串口读取数据。它们采用小端字节序,但我需要独立于平台,因此我必须覆盖double. 我找不到任何地方,如何做到这一点,所以我编写了自己的函数。但我不确定。(而且我没有大端机器来尝试)。
这能正常工作吗?还是有一些我找不到的更好的方法?
double get_double(uint8_t * buff){
double value;
memcpy(&value,buff,sizeof(double));
uint64_t tmp;
tmp = le64toh(*(uint64_t*)&value);
value = *(double*) &tmp;
return value;
}
Run Code Online (Sandbox Code Playgroud)
ps 我计算的是double8 个字节长,所以请不要理会这个。我知道这可能有问题
编辑:经过建议,我应该使用联合,我这样做了:
union double_int{
double d;
uint64_t i;
};
double get_double(uint8_t * buff){
union double_int value;
memcpy(&value,buff,sizeof(double));
value.i = le64toh(value.i);
return value.d;
}
Run Code Online (Sandbox Code Playgroud)
更好的?(虽然我没看出有多大区别)
EDIT2:尝试#3,你现在怎么想?
double get_double(uint8_t * buff){
double value;
uint64_t tmp;
memcpy(&tmp,buff,sizeof(double));
tmp = le64toh(tmp);
memcpy(&value,&tmp,sizeof(double));
return value;
}
Run Code Online (Sandbox Code Playgroud)
Edit3:我用它编译gcc -std=gnu99 -lpthread -Wall -pedantic
Edit4:在下一个建议之后,我添加了一个字节顺序检查的条件。老实说,我不知道我现在在做什么(不应该有类似的事情吗__DOUBLE_WORD_ORDER__?)
double get_double(uint8_t * buff){
double value;
if (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__){
uint64_t tmp;
memcpy(&tmp,buff,sizeof(double));
tmp = le64toh(tmp);
memcpy(&value,&tmp,sizeof(double));
}
else {
memcpy(&value,buff,sizeof(double));
}
return value;
}
Run Code Online (Sandbox Code Playgroud)
我只需手动将字节复制到临时双精度值,然后返回它。在 C 中(我认为是 C++),可以将任何指针强制转换为char *; 正如我在评论之一中提到的,这是别名的明确权限之一(在标准草案 n1570,第 6.5/7 段中)。为了完成任何接近硬件的事情,例外是绝对必要的;包括反转通过网络接收的字节:-)。
遗憾的是,没有标准的编译时方法来确定是否有必要;如果您想避免分支,这在处理大量数据时可能是个好主意,您应该查找编译器的文档以获取专有定义,以便您可以在编译时选择正确的代码分支。例如,gcc已__FLOAT_WORD_ORDER__设置为__ORDER_LITTLE_ENDIAN__或__ORDER_BIG_ENDIAN__。
(因为你在评论中提出的问题:__FLOAT_WORD_ORDER__一般来说是指浮点。如果设计一个针对不同数据大小具有不同字节顺序的 FPU,那将是一个非常病态的想法:-)。实际上,没有多少主流体系结构对浮点类型和整数类型具有不同的字节顺序。正如维基百科所说,小型系统可能会有所不同。)
Basile 指出ntohd,这是 Windows 上存在但 Linux 上显然不存在的转换函数。
我天真的示例实现就像
/** copy the bytes at data into a double, reversing the
byte order, and return that.
*/
double reverseValue(const char *data)
{
double result;
char *dest = (char *)&result;
for(int i=0; i<sizeof(double); i++)
{
dest[i] = data[sizeof(double)-i-1];
}
return result;
}
/** Adjust the byte order from network to host.
On a big endian machine this is a NOP.
*/
double ntohd(double src)
{
# if !defined(__FLOAT_WORD_ORDER__) \
|| !defined(__ORDER_LITTLE_ENDIAN__)
# error "oops: unknown byte order"
# endif
# if __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__
return reverseValue((char *)&src);
# else
return src;
# endif
}
Run Code Online (Sandbox Code Playgroud)
这里有一个工作示例: https: //ideone.com/aV9mj4。
改进的版本将迎合给定的 CPU——它可能有一个 8 字节交换命令。