C, binary fopen, read data range from bytes


Linux-SWAT

Forum Addict!
Joined
Feb 13, 2010
Messages
9,188
Hi,

I've used fopen with the b flag on a binary file.

I can read the octets (8 bit bytes) one by one from the start with a loop, no problem.

But let's say I have at the start of the file:
12 23 34 45 56 67 78 89 90 etc.

I need to read the little endian data part corresponding to
89 78 67 56
And store it into an int or a string or whatever.

What is the proper way to do that ?

I've encountered some trouble like:
-when looping, file[0] is not a char, it's an octet (two chars) so I had problems using memcpy() (segfault)
-using just printf, 00 appear to be 0, 01 -> 1, which is normal but I fear it can be troublesome
-at some point I wondered if I should add every octet after having multiplied it before with its weight (very naive example e.g. in order 11 22 = 11*100 + 22). I guess this is an awful idea but I was stuck (and I am still).
-htonl() is sexy but I don't see if it can be useful in this context
-I also wondered if it can be more natural to go to the binary level
 
I'm not sure if I understand your question correctly to be honest.
What exactly is stopping your from doing a fread() into an int pointer? You're most likely on a little endian machine and if you're not you could just swap the bytes afterwards.

Also, isn't an octet supposed to be 8 bits, so one byte? How is that two chars?
I feel like I'm missing something here. Perhaps it's obvious.
What is your file variable anyways? Afaik you are not supposed to access the FILE object returned by fopen directly.
 
I do C once every 10 years so I probably forgot simple things like the fread() you're suggesting.
Octet is indeed 8 bit, but a byte can be an arbitrary number of bits depending on the platform.
I thought that file[0] must return one char, so like 0 to F. As I read octets, I can't fit lets say FF into one zone of a char tab[].
Yup, I'm accessing the file object, but TBH, I don't really understand what I'm reading.
 
Well, one char would be 0 to FF. If you want to write the values in hex representation as a string, that would be a bit different of course. In that case you could printf do the conversion for you (use "%x" or "%X").
I'm not sure how relevant non-8-bit bytes are nowadays, really. What machine is this code supposed to run on?

You may get what you want from reading the FILE pointer directly, but this is an implementation detail then.
I'm usually using C++, so there's that. I'm still not sure what you're trying to achieve, though.
 
How are you reading the bytes? I have testing using getc(fh) and it returns an int. I could then fprint that padded with 0s to the approproate length to print out two chars per int:
Code:
fprint("%02d",i); /* where i is the int you just read */
 
I'm more confused than I thought... Yeah, of course a char can't be stored on a nibble...

It's currently for PC, but some electronicians still don't like to use the word "byte" as it can be confusing, and "octet" is not yet widely used.

I just want to read a section of octets in a file, which is stored in reverse order (as in the example in the 1st post).

Ok, so the padding should be useful only in printf. I was expecting that, but since I can't compare with a hexdump I wasn't sure.
 
How many bytes (8-bit) long are your words? You'll need to read all of those and then shift them into position I guess. Say you're reading 16-bit numbers (two bytes each), you can do something like:
Code:
i=getc(fh)+getc(fh)<<8
I guess your i would need to be created as a long or something, because iirc ints are 8-bit intrinsically.

Detecting your end code might be tricky, although if you're numbers are 32-bits long those four bytes will just be the one long number, and you can detect that and terminate your loop.
 
It's currently for PC, but some electronicians still don't like to use the word "byte" as it can be confusing, and "octet" is not yet widely used.
There's no CPU still in use that I know of which does not use 8bit bytes, you'd have to enter more obscure grounds like DSPs to encounter that. If you seriously want to cover that you can't get around doing everything though bitwise operations, char is the very definition of the smallest type of data you can operate on without further restrictions. There's no universal way to do it, you'll always have to find a data type of a known bit width and endianess as a base of operation - with a single byte being useful for not having any endianess to care about.

With most chips being little endian and network packages being big endian you usually have conversion macros available with everything network related.

If you can program it with plain ISO-C, it's pretty much safe to just assume that a byte has 8 bits. Such exotic hardware tends to use some kind of non-standard C dialect instead.
 
I have to read 4 octets so 8x4=32 so yes it's a long.

The byte/octet discussion is only about semantics, I'm on a PC, but surrounded by electronicians.
 
So, in your example the four end byts (the end 32-bit word) lie on a 32-bit boundary. Is that defined behaviour, or just a coincidence?

I'm also a little confused as to your use of memcpy. You are copying into a previously malloced heap area, right? Are you just copying all of the data (including or excluding the end code?) or doing something more refined with it?
 
So you want to read in a big endian stored integer into a little endian processor?
Code:
byte bytedata[4];

uint32 intdata = bytedata[0] + (bytedata[1]<<8) + (bytedata[2]<<16) + (bytedata[3]<<24);
 
This is a coincidence, I have to read a random range at a random position.

No it's little endian data -> little endian cpu, It's the first time I ever read binary data in a file so I may look dumb here :^) .
 
I was able to do the stuff with fseek and fread.

My main problem was that I wanted to read the already fread and buffered data instead of simply fread it...

Many thanks everyone.
 
He needs to read 32-bit longs. Whether it's better to use 'b' mode or not, I'm not sure - in python I've found even non-b mode doesn't mangle line endings or anything, so you can still use it for byte reads if you prefer a character output rather than a bytes object.

Edit: I was replying to @ptitSeb, but @LinuxSWAT's reply above mine makes mine somewhat irrelevant here, I think. But I'll just leave it here since I don't really understand what he's doing still.
 
one point I dont think was made that might help in the future is that you can cast a pointer to size you need.

For example say you read the data into an byte arrar:

unsigned char *mybuffer;

You can cast that to a new pointer that you can around by 4 byte jumps

unsigned long *longbuffer = (unsigned long *) mybuffer;

So if your buffer is 0xAB 0xCD 0xEF 0x11

*mybuffer (0) returns 0xAB
mybuffer++
*mybuffer (1) returns 0xCD

*longbuffer (0) returns 0xAB 0xCD
longbuffer++
*longbuffer (1) returns 0xEF 0x11
 
Back
Top