Как перекрестная платформа - обработка буфера протокола Google типами плавающих точек на практике?

Буферы протокола Google Protocol позволяет хранить поплавки и удваиваться в сообщениях. Я просматривал исходный код в реализации, задаваюсь вопросом, как им удалось сделать это в кроссплатформе, и то, что я наткнулся:

inline uint32 WireFormatLite::EncodeFloat(float value) {
  union {float f; uint32 i;};
  f = value;
  return i;
}

inline float WireFormatLite::DecodeFloat(uint32 value) {
  union {float f; uint32 i;};
  i = value;
  return f;
}

inline uint64 WireFormatLite::EncodeDouble(double value) {
  union {double f; uint64 i;};
  f = value;
  return i;
}

inline double WireFormatLite::DecodeDouble(uint64 value) {
  union {double f; uint64 i;};
  i = value;
  return f;
}

Теперь, важная дополнительная информация заключается в том, что эти процедуры не являются концом процесса Но скорее, результат их пост обрабатывается, чтобы поставить байты в малоэндандский порядок:

inline void WireFormatLite::WriteFloatNoTag(float value,
                                        io::CodedOutputStream* output) {
  output->WriteLittleEndian32(EncodeFloat(value));
}

inline void WireFormatLite::WriteDoubleNoTag(double value,
                                         io::CodedOutputStream* output) {
  output->WriteLittleEndian64(EncodeDouble(value));
}

template <>
inline bool WireFormatLite::ReadPrimitive(
    io::CodedInputStream* input,
    float* value) {
  uint32 temp;
  if (!input->ReadLittleEndian32(&temp)) return false;
  *value = DecodeFloat(temp);
  return true;
}

template <>
inline bool WireFormatLite::ReadPrimitive(
    io::CodedInputStream* input,
    double* value) {
  uint64 temp;
  if (!input->ReadLittleEndian64(&temp)) return false;
  *value = DecodeDouble(temp);
  return true;
}

Итак, мой вопрос: это действительно достаточно хорошо на практике, чтобы обеспечить ли это сериализацию поплавков и двойников в C ++ Платформы?

Я явно вставляю слова «на практике» в моем вопросе, потому что я знаю, что теоретически Нельзя делать какие-либо предположения о том, как поплавки и двойники фактически отформатированы в C ++, но я понимаю Имейте ощущение ли эта теоретическая опасность на самом деле что-то, что я должен быть очень обеспокоен на практике.

Обновление

Теперь он смотрит на меня, как подход PB получается, может быть сломан на SPARC. Если я понимаю Эта страница Oracle, описывающая формат, используемый для числа на SPARC правильно, SPARC использует противоположный Endian в виде x86 для целых чисел , но тот же endian, что и X86 для поплавков и удваивает . Тем не менее, кодирует PB поплавки / удваивает, сначала избивая их непосредственно к целочисленному типу соответствующего размера (через средства профсоюза; см. Фрагменты кода, указанные в моем вопросе выше), а затем обратный порядок байтов на платформах с Целые числа Big-Endian:

void CodedOutputStream::WriteLittleEndian64(uint64 value) {
  uint8 bytes[sizeof(value)];

  bool use_fast = buffer_size_ >= sizeof(value);
  uint8* ptr = use_fast ? buffer_ : bytes;

  WriteLittleEndian64ToArray(value, ptr);

  if (use_fast) {
    Advance(sizeof(value));
  } else {
    WriteRaw(bytes, sizeof(value));
  }
}

inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value,
                                                            uint8* target) {
#if defined(PROTOBUF_LITTLE_ENDIAN)
  memcpy(target, &value, sizeof(value));
#else
  uint32 part0 = static_cast(value);
  uint32 part1 = static_cast(value >> 32);

  target[0] = static_cast(part0);
  target[1] = static_cast(part0 >>  8);
  target[2] = static_cast(part0 >> 16);
  target[3] = static_cast(part0 >> 24);
  target[4] = static_cast(part1);
  target[5] = static_cast(part1 >>  8);
  target[6] = static_cast(part1 >> 16);
  target[7] = static_cast(part1 >> 24);
#endif
  return target + sizeof(value);
}

Это, однако, это именно то неправильная вещь, которую нужно делать в случае поплавка / удваивания на SPARC, поскольку байты уже в «правильном» порядке.

Так что в заключение, если мое понимание правильно, то число с плавающей точкой нет . ) Как целые числа на данной платформе, что является неверным предположением, чтобы сделать на SPARC.

Обновление 2

Как отметила Lyke Out, IEEE 64-битные точки плавающих точек , хранящиеся в Big-Endian по заказу на SPARC, в отличие от X86. Однако только два 32-битных слова находятся в обратном порядке, а не все 8 байтов, и в частности, 32-разрядные плавающие точки IEEE выглядят так, как они хранятся в том же порядке, что и на X86.

22
задан Gregory Crosswhite 30 August 2011 в 20:54
поделиться