C, binary fopen, read data range from bytes

Linux-SWAT

Hardcore Member
Joined
Feb 13, 2010
Messages
8,274
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
 

elvissteinjr

Very Active Member
Joined
Jun 19, 2010
Messages
681
Age
23
Location
Germany
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.
 

Linux-SWAT

Hardcore Member
Joined
Feb 13, 2010
Messages
8,274
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.
 

elvissteinjr

Very Active Member
Joined
Jun 19, 2010
Messages
681
Age
23
Location
Germany
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.
 

levi

Still fresh, damnit!
Joined
Oct 6, 2008
Messages
11,953
Location
Somewhere off the coast of the EU
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 */
 

Linux-SWAT

Hardcore Member
Joined
Feb 13, 2010
Messages
8,274
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.
 

levi

Still fresh, damnit!
Joined
Oct 6, 2008
Messages
11,953
Location
Somewhere off the coast of the EU
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.
 

Letalis Sonus

Advanced Member
Joined
Mar 5, 2009
Messages
1,321
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.
 

Linux-SWAT

Hardcore Member
Joined
Feb 13, 2010
Messages
8,274
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.
 

levi

Still fresh, damnit!
Joined
Oct 6, 2008
Messages
11,953
Location
Somewhere off the coast of the EU
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?
 

pmprog

DNF (Did Not Finish)
Joined
Apr 25, 2011
Messages
3,943
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);
 

Linux-SWAT

Hardcore Member
Joined
Feb 13, 2010
Messages
8,274
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 :^) .
 

Linux-SWAT

Hardcore Member
Joined
Feb 13, 2010
Messages
8,274
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.
 

levi

Still fresh, damnit!
Joined
Oct 6, 2008
Messages
11,953
Location
Somewhere off the coast of the EU
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.
 

Pickle

Mega GP Mania
Joined
May 30, 2006
Messages
5,462
Location
Detroit, Michigan
Website
Visit site
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
 
Top