Message-Id: <200002241533.KAA31955@delorie.com> From: "Dieter Buerssner" To: Eli Zaretskii Date: Thu, 24 Feb 2000 16:46:33 +0100 MIME-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7BIT Subject: Re: binary to float CC: djgpp AT delorie DOT com References: <890r5l$1qjno$1 AT fu-berlin DOT de> In-reply-to: X-mailer: Pegasus Mail for Win32 (v3.12b) Reply-To: djgpp AT delorie DOT com 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