如何从网络管理双重的字节顺序

时间:2013-02-26 00:55:19

标签: c++ c network-programming endianness libpq

我对这个问题Swap bits in c++ for a double

的回答有一个大问题

然而,这个问题或多或少是我搜索的内容:  我从网络收到一个双,我想在我的机器上正确编码。


在我收到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));
}

但是,如果我引用this site

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建议的尽管未在OP问题的标题中准确说明的结束的网络管理程度)。

最后:我应该将double分成4个字节的两个部分,并在这两个部分上应用ntohl功能吗?还有更多的经典解决方案吗?

在C host to network double?中也存在这个有趣的问题,但它限制为32位值。答案说,由于架构差异,双打应该转换为字符串......我也会使用音频样本,我是否真的考虑将所有样本转换为数据库中的字符串? (双打来自我通过网络查询的数据库)

3 个答案:

答案 0 :(得分:2)

如果您的双打是IEEE 754格式,那么您应该相对正常。现在你必须将它们的64位分成两个32位,然后以big-endian顺序传输它们(这是网络顺序);

怎么样:

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));
}

答案 1 :(得分:1)

假设您有一个编译时选项来确定字节顺序:

#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兼容 - 有些机器使用其他浮点格式...例如,字符串可以更好地工作......

答案 2 :(得分:1)

我无法让JohnKä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类型的结构。

如果你真的希望双重作为两个整数

double d;
int* data = reinterpret_cast<int*>(&d);

int first = data[0];
int second = data[1];

最后,long int并不总是64位整数(我必须使用long long int在我的机器上创建64位int)。