This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: ints, floats and chars


Hi Evert,

Your question is off topic for this forum.  You question is a general C
question, and not a question about GCC-isms in particular.

Anyway...

Here's what I do.  (Using a slightly different example from yours.)

[I'm a C++ programmer, so pardon my C code if C++-isms creep in.]

Let's say I am working with a data structure that is going to be used on 5
different platforms.  Platforms are a mix of big-endian and little-endian.
4 of the 5 platforms use IEEE 754, but one platform, Zinglehoffer, uses
(made up) 128-bit High Precision Floating Point for both float and double.

Another platform, (made up) Seymour, uses 32-bit char, short, int.  (32-bit
addressable bytes.)

// In memory structure.
struct Foo
{
  char c;   // 8-bit nonsigned char
  // <--- may be padding bytes here.
  int s;    // 32-bit signed int
  float f;  // 32-bit IEEE 754
  // <--- may be padding bytes here.
  double d; // 64-bit IEEE 754
  char c2;  // 8-bit nonsigned char
  // <--- may be alignement bytes here.
};

Notice that on the Zinglehoffer, float and double are 128-bit.

And on Seymour, char is 32-bit.

// The "save to disk" and "over the wire" packet.
typedef char byte; // or typedef char octet if you prefer.
struct FooRecord
{
  byte c[1];
  byte s[4];
  byte f[4];
  byte d[4];
  byte c2[1];
};

void FooToStore(struct FooRecord* buf, struct Foo const* foo)
{
  buf->c[0] = foo->c;
  hton_int(buf->s, foo->s); // Converts the int into big-endian order.
  hton_float(buf->f, foo->f); // Converts float to 32-bit IEEE 754
  hton_double(buf->d, foo->d); // Converts double to 64-bit IEEE 754
  buf->c2[0] = foo->c2;
}

void FooFromStore(struct Foo* foo, struct FooRecord const* buf)
{
// memset(foo, 0x00, sizeof(struct foo)); // for the paranoid
  foo->c = buf->c[0];
  ntoh_int(&foo->s, buf->s); // Big-endian buf to host-endian int.
  ntoh_float(&foo->f, buf->f); // Canonical IEEE 754 to host float.
  ntoh_double(&foo->d, buf->d); // Canonical IEEE 754 to host double.
  foo->c2 = buf->c2;
}

The memset will scrub the padding and alignment bytes to zero, if that
matters to you.

I'll leave the ntoh (network-to-host) and hton (host-to-network) routines as
an exercise.  Note:  by long standing convention, network byte order is
big-endian.

Also note, on the Seymour 32-bit byte system, the routines to READ and WRITE
a the buffer to the disk or over the wire have to unpack and pack the 32-bit
byte from/to 8-bit "bytes" (octets).

Also note, on the Zinglehoffer system, the ntoh_float, ntoh_double,
hton_float and hton_double will have to do the conversion of the
Zinglehoffer 128-bit float & double to 32-bit & 64-bit IEEE 754,
respectively.

If you follow this guideline, you will have a much better time with I/O
(whether to disk or over the wire) and portability.  Even portability to
different compilers, or different versions of the same compiler, or same
compiler with various flag affecting padding and alignment.  If you don't
follow this guideline, you do so at your own peril.

HTH,
--Eljay

q.v. http://en.wikipedia.org/wiki/IEEE_754


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]