delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2000/02/24/10:47:30

Message-Id: <200002241533.KAA31955@delorie.com>
From: "Dieter Buerssner" <buers AT gmx DOT de>
To: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
Date: Thu, 24 Feb 2000 16:46:33 +0100
MIME-Version: 1.0
Subject: Re: binary to float
CC: djgpp AT delorie DOT com
References: <890r5l$1qjno$1 AT fu-berlin DOT de>
In-reply-to: <Pine.SUN.3.91.1000224122613.13848S-100000@is>
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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019