如何从网络上管理double的endianes

How to manage endianess of double from network

本文关键字:double endianes 管理 网络      更新时间:2023-10-16

我对这个问题的答案有一个大问题用c++中的比特交换双

然而,这个问题或多或少是我所寻找的:我从网络收到一个替身,我想在我的机器中正确编码。


在我收到int的情况下,我使用ntohl:执行此代码

int * piData = reinterpret_cast<int*>((void*)pData);
//manage endianness of incomming network data 
unsigned long ulValue = ntohl(*piData);
int iValue = static_cast<int>(ulValue);

但如果我收到double,我不知道该怎么办。

这个问题的答案建议做:

template <typename T>
void swap_endian(T& pX)
{
    char& raw = reinterpret_cast<char&>(pX);
    std::reverse(&raw, &raw + sizeof(T));
}

然而,如果我引用这个网站:

The ntohl() function converts the unsigned integer netlong from network byte order to host byte order. When the two byte orders are different, this means the endian-ness of the data will be changed. When the two byte orders are the same, the data will not be changed.

相反,@GManNickG对问题的回答总是用std::reverse进行反演

考虑到这个答案是假的,我错了吗?(在使用ntohl表明的endianes的网络管理范围内,尽管在OP问题的标题中没有确切地说明(。

最后:我应该把double分成4个字节的两部分,并在这两部分上应用ntohl函数吗?还有更多的罐头解决方案吗?

C中还有一个有趣的问题,主机到网络的双重性?,但是它限制为32比特的值。答案是,由于体系结构的差异,双打应该转换为字符串。。。我还将处理音频样本,我真的应该考虑将数据库中的所有样本转换为字符串吗?(双打来自我在网络上查询的数据库(

如果您的double是IEEE 754格式的,那么您应该相对可以。现在您必须将它们的64位分成两个32位的两半,然后以大端顺序(即网络顺序(传输它们;

怎么样:

void send_double(double d) {
    long int i64 = *((reinterpret_cast<int *>)(&d)); /* Ugly, but works */
    int hiword = htonl(static_cast<int>(i64 >> 32));
    send(hiword);
    int loword = htonl(static_cast<int>(i64));
    send(loword);
}
double recv_double() {
    int hiword = ntohl(recv_int());
    int loword = ntohl(recv_int());
    long int i64 = (((static_cast<long int>) hiword) << 32) | loword;
    return *((reinterpret_cast<double *>(&i64));
}

假设您有一个编译时选项来确定endianness:

#if BIG_ENDIAN
template <typename T>
void swap_endian(T& pX)
{
   // Don't need to do anything here... 
}
#else
template <typename T>
void swap_endian(T& pX)
{
    char& raw = reinterpret_cast<char&>(pX);
    std::reverse(&raw, &raw + sizeof(T));
}
#endif

当然,另一种选择是根本不通过网络发送double——考虑到它不能保证与IEEE-754兼容——还有一些机器使用其他浮点格式。。。例如,使用字符串会更好。。。

我无法让John Källén代码在我的机器上工作。此外,将double转换为字节(8位,1个字符(可能更有用:

template<typename T>
string to_byte_string(const T& v)
{
    char* begin_ = reinterpret_cast<char*>(v);
    return string(begin_, begin_ + sizeof(T));
}
template<typename T>
T from_byte_string(std::string& s)
{
    assert(s.size() == sizeof(T) && "Wrong Type Cast");
    return *(reinterpret_cast<T*>(&s[0]));
}

此代码也适用于使用POD类型的结构。

如果你真的想双作为两个int

double d;
int* data = reinterpret_cast<int*>(&d);
int first = data[0];
int second = data[1];

最后,long int并不总是64位整数(我不得不使用long long int在我的机器上生成64位int(。

如果您想了解系统无端

#if __cplusplus > 201703L

#include <bit>
#include <iostream>
using namespace std;
int main()
{
    if constexpr (endian::native == endian::big)
        cout << "big-endian";
    else if constexpr (endian::native == endian::little)
        cout << "little-endian";
    else
        cout << "mixed-endian";
}

有关更多信息:https://en.cppreference.com/w/cpp/types/endian