如何改变双精度字节序?

Cha*_*one 5 c endianness

我需要从串口读取数据。它们采用小端字节序,但我需要独立于平台,因此我必须覆盖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)

Pet*_*ica 5

我只需手动将字节复制到临时双精度值,然后返回它。在 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 字节交换命令。