Mail Archives: djgpp/2000/02/24/10:47:30
On 24 Feb 00, at 12:26, Eli Zaretskii wrote:
> On 23 Feb 2000, Dieter Buerssner wrote:
>
> > The only problem may arise from the endianess of the format.
> > If you have to swap endianess, the following code snippet may
> > work. (untested)
> >
> > FILE *fp;
> > unsigned char rawdata[4];
> > unsigned char t;
> > float x;
> >
> > fp = fopen("binfloat.dat", "rb");
> > if (fp)
> > {
> > if (fread(rawdata, sizeof rawdata, 1, fp) == 1)
> > {
> > /* swap endianess */
> > t = rawdata[0]; rawdata[0] = rawdata[3]; rawdata[3] = t;
> > t = rawdata[1]; rawdata[1] = rawdata[2]; rawdata[2] = t;
> > x = *(float *)rawdata; /* x is the float you wanted */
> > }
> > }
Obviously, in my example, I assumed that the binary floating point
data is stored in big endian format in a file. This was the only
situation, I could imagine, where you would need to convert
the floating point representation. Because of Elis followup, I
recognized, that the same situation may arise, when reading data from
some network.
> There are library functions (htons, ntohl, etc.) to do this more
> portably.
I think, you mean something like:
unsigned long l;
float x;
fread(&l, sizeof l, 1, fp);
l = ntohl(l);
x = *(float *)&l;
My question, is this really more portable? In the libc info for ntohl
under Portability I read: not ANSI, not POSIX. Is this function
generally available? Also, one other problem might arise when
unsigned long is 64bit (i.e. Alpha, which uses IEEE floating point).
My code assumes, that CHAR_BIT == 8, and that external and internal
floating point formats are of different endianess. You are correct,
that the later assumption would not be needed, when using ntohl.
The external format must be defined somehow (in this particular
problem this seems to be IEEE 4 byte floats, in big endian format). I
think the most portable solution could be, to check the internal
floating point format at run time. This could be done by checking the
internal encoding of some floating point constant, of which the IEEE
binary representation is known.
/* Choose MAGIC_FLOAT so, that all four bytes in the IEEE float are
different. */
float f = MAGIC_FLOAT;
/* internel rep. in big endian format */
unsigned char c[4] = {MAGIC0,MAGIC1,MAGIC2,MAGIC3};
unsigned char *cp;
if (CHAR_BIT != 8 || sizeof(float) != 4)
give up;
cp = (unsigned char *)&f;
if (cp[0] == MAGIC0 && cp[1] == MAGIC1
&& cp[2] == MAGIC2 && cp[3] == MAGIC3)
/* Internal float format is big endian, can use fread without byte
swapping */
...
else if (cp[0] == MAGIC3 && cp[1] == MAGIC2
&& cp[2] == MAGIC1 && cp[3] == MAGIC0)
/* Internal float format is little endian, use fread with byte
swapping */
...
else
/* Internal format is either some mixed endian, like PDP11 (which
does not have IEEE floating point), or it is not an IEEE floating
point format at all, or the compiler is broken and is not able to
convert MAGIC_FLOAT to binary correctly */
give up;
}
Do you think this is portable?
Regards,
Dieter
- Raw text -