我需要从串口读取数据。它们是小端的,但我需要独立于平台,所以我必须覆盖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;
}
P.S。我估计double
长8个字节,所以不要为此烦恼。我知道这个可能有问题
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;
}
更好? (虽然我没有看到太多差异)
EDIT2:attemtp#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;
}
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;
}
答案 0 :(得分:2)
我只是去手动将字节复制到临时双,然后返回。在C(我认为是C ++)中,可以将任何指针转换为char *
;这是别名的显式权限之一(在标准草案n1570,参数6.5 / 7中),正如我在其中一篇评论中提到的那样。为了完成接近硬件的任何事情,这个例外是绝对必要的;包括通过网络收到的反转字节: - )。
没有标准的编译时间方法来确定这是否是必要的,这是可惜的;如果你想避免分支,如果你处理大量数据可能是一个好主意,你应该查找编译器的专有定义文档,以便你可以在编译时选择正确的代码分支。 gcc, for example,已将__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
}
这里有一个有效的例子:https://ideone.com/aV9mj4。
改进的版本可以满足给定的CPU - 它可能有一个8字节的交换命令。
答案 1 :(得分:1)
如果您可以调整软件的两面(发射器和接收器),您可以使用一些serialization库和格式。它可以在您的案例中使用旧的XDR例程,例如xdr_double
(请参阅xdr(3) ...)。您还可以考虑ASN1或使用JSON等文字格式。
XDR是big endian。你可能试图找到一些NDR实现,是小端。
另请参阅this相关问题,以及htond
答案 2 :(得分:1)
好的,最后,感谢大家,我找到了最好的解决方案。现在我的代码看起来像这样:
double reverseDouble(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;
}
double get_double(uint8_t * buff){
double value;
memcpy(&value,buff,sizeof(double));
if (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
return reverseDouble((char *)&value);
else
return value;
}
P.S。 (检查定义等是在其他地方)