Read n bytes from file

  • Thread starter Alexander Hunziker
  • Start date
A

Alexander Hunziker

Hello group,

I have a program that reads data from a binary file. I know that at some
known position in the file there are 12 4 bytes long floating point
numbers. Here's how I read them now:

float temptriangle[12];

fread(&temptriangle, 4, 12, fp);

This works quite nicely, however it does so only if sizeof(float) is 4,
otherwise I'll get garbage.

Is there a cleaner way of doing it? Reading 4 bytes from a file into a
floating point variable?

Thanks in advance for your help,
Alex
 
E

Eric Sosman

Alexander said:
Hello group,

I have a program that reads data from a binary file. I know that at some
known position in the file there are 12 4 bytes long floating point
numbers. Here's how I read them now:

float temptriangle[12];

fread(&temptriangle, 4, 12, fp);

This works quite nicely, however it does so only if sizeof(float) is 4,
otherwise I'll get garbage.

Is there a cleaner way of doing it? Reading 4 bytes from a file into a
floating point variable?

"Cleanliness is next to Godliness and next to impossible,
too." You are aware, I hope, that different C implementations
use different binary representation for `float', so your binary
file may be meaningful only to the machine that wrote it. You
have already sacrificed a certain amount of cleanliness by
choosing to use a binary format.

That said, the code as written can be scrubbed to a somewhat
brighter gleam. First, get rid of the address-of `&' operator;
see Question 6.12 in the comp.lang.c Frequently Asked Questions
(FAQ) list <http://www.eskimo.com/~scs/C-faq/top.html> if you
don't understand why this is the right thing to do. Second,
you can rewrite the "magic numbers" `4' and `12' in terms of
the `sizeof' operator. This would give something like

fread(temptriangle, sizeof temptriangle[0],
sizeof temptriangle / sizeof temptriangle[0], fp);

(The third argument is correct only if `temptriangle' is an
actual array rather than a pointer; see Question 6.21 in the FAQ.)

Even this isn't quite as clean as it should be, because it
lacks one important feature: it doesn't check whether fread()
succeeded or failed. You really need something more like

if (fread(temptriangle, ...)
!= sizeof temptriangle / sizeof temptriangle[0])
complain_and_die();

See the Sixth Commandment at
<http://www.lysator.liu.se/c/ten-commandments.html>.
 
G

Gordon Burditt

I have a program that reads data from a binary file. I know that at some
Second,
you can rewrite the "magic numbers" `4' and `12' in terms of
the `sizeof' operator.

I'll disagree here. The file format spec said it had floating point
numbers that are *FOUR* bytes long. This is independent of the
sizeof(float) on the target machine.

The file format spec also said there were *TWELVE* numbers, not
the number in any particular array. It is quite possible that
someone might re-use the array later for a set of 17 numbers.

Gordon L. Burditt
 
L

Lawrence Kirby

Hello group,

I have a program that reads data from a binary file. I know that at some
known position in the file there are 12 4 bytes long floating point
numbers. Here's how I read them now:

float temptriangle[12];

fread(&temptriangle, 4, 12, fp);

This works quite nicely, however it does so only if sizeof(float) is 4,
otherwise I'll get garbage.

The question is whether you know that the format of the floating point
values in the file corresponds to the representation used by float on your
implementation. If it does then fine if it doesn't then clearly this won't
work. And of sizeof(float) is not 4 then clearly the format/representation
differs. It could differ even if sizeof(float)==4.
Is there a cleaner way of doing it? Reading 4 bytes from a file into a
floating point variable?

To make the code general you would have to interpret the bit pattern of
each float in the file data and build values from that.

Lawrence
 
G

Giorgos Keramidas

I'll disagree here. The file format spec said it had floating point
numbers that are *FOUR* bytes long. This is independent of the
sizeof(float) on the target machine.

The file format spec also said there were *TWELVE* numbers, not
the number in any particular array. It is quite possible that
someone might re-use the array later for a set of 17 numbers.

Even so, "magic" constants are evil. Use #define and a nice block of
comments to describe their "magic" values.

- Giorgos
 
E

Eric Sosman

Gordon said:
I'll disagree here. The file format spec said it had floating point
numbers that are *FOUR* bytes long. This is independent of the
sizeof(float) on the target machine.

That's a possible interpretation. I read the O.P. a bit
differently, believing that when he wrote "4" he meant "the
size of the local `float'." The example code (which you
snipped) suggests that the file holds images of the local
`float' and not some independently-specified format. If the
file format *isn't* native, a lot more work is needed.
The file format spec also said there were *TWELVE* numbers, not
the number in any particular array. It is quite possible that
someone might re-use the array later for a set of 17 numbers.

Yes; it's possible that "12" is non-magical. It is, after
all, a peculiar number of values with which to describe a triangle.
(One might even say it's an "odd" number of values ;-). Three
points with four values each -- X,Y,Z,T? X,Y,dX/dT,dY/dT?
 
M

Malcolm

Alexander Hunziker said:
float temptriangle[12];

fread(&temptriangle, 4, 12, fp);

This works quite nicely, however it does so only if sizeof(float) is 4,
otherwise I'll get garbage.

Is there a cleaner way of doing it? Reading 4 bytes from a file into a
floating point variable?

Reconstruct the floating point number from binary.

/*
portable read of binary float.
Note untested guide code to show the principle only. Your exact floating
point format may differ. */
*/
float readfloat(FILE *fp)
{
unsigned char byte1;
unsigned char byte1;
unsigned char byte2;
unsigned char byte3;
int sign;
int exponent;
int mantissa;
double answer;

byte0 = fgetc(fp);
byte1 = fgetc(fp);
byte2 = fgetc(fp);
byte3 = fgetc(fp);

sign = byte0 & 0x80 ? 1 : 0;
exponent = ((byte0 & 0x7F) << 1) + ((byte1 & 0x80) >> 7);
mantissa = ((byte1&0x7F) << 16) + (byte2 << 8) + byte3;

if(exponent == 0 || exponent == 0xFF)
{
/* these are denormalised numbers, nans, and other horrible things
handle specially or reject. Zero you are likely to need */
if( byte0 == 0 && byte1 == 0 && byte2 == 0 && byte3 == 0)
return 0;
}
exponent -= 0x80;
/* reconstruct the floating point number. It is in the form (1 + mantissa)
* 2 ^ exponent */
answer = (((double)mantissa) / 0x800000 + 1.0) * pow(2, exponent);

if(sign)
answer = -answer;

return (float) answer;

}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top