У меня БОЛЬШАЯ проблема с ответом на этот вопрос Поменяйте биты в С ++ для двойного
Тем не менее, этот вопрос более или менее то, что я ищу:
Я получаю дубликат из сети и хочу правильно закодировать его на своем компьютере.
В случае, если я получаю 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
предложить, хотя это не было точно сказано в названии вопроса ОП).
В конце концов: я должен разделить double
на две части по 4 байта и применить ntohl
функция на две части? Есть ли еще канонические решения?
Там также этот интересный вопрос в C, хост в сеть двойной?, но он ограничивается 32-битными значениями. И ответ говорит, что двойные числа должны быть преобразованы в строки из-за различий в архитектуре … Я также собираюсь поработать с аудио-сэмплами, стоит ли мне действительно подумать о преобразовании всех сэмплов в строки в моей базе данных? (удваивается из базы данных, которую я запрашиваю по сети)
Если ваши двойники в формате 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));
}
Предполагая, что у вас есть опция времени компиляции для определения порядка байтов:
#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 — есть машины, использующие другие форматы с плавающей запятой … Использование, например, строки будет работать намного лучше …
Я не мог заставить код Джона Келлена работать на моей машине. Кроме того, может быть более полезно преобразовать двойное число в байты (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 на моей машине).