J
James Harris
Jorgen Grahn said:This comes up often in this group.
I knew it was an old 'chestnut'! Hopefully the constraints I included made
it less boring than just asking how to align fields.
As far as I'm concerned, the standard approach for all binary I/O is
not to pretend the I/O buffers map to the in-memory representation of
some C data structure. Treat it as a buffer of N 8-bit octets instead
if that is what it is:
// assuming uint8_t is available, and that
// FAT uses little-endian encoding
const uint8_t * p = something();
p += 8;
unsigned bps = get16_le(p); p += 2;
unsigned spc = *p++;
unsigned blahblah = get16_le(p); p += 2;
You mention not wanting to do something "basic and slow" ... well, the
above is basic and /should/ be slow -- but (a) is that still true
today, with caches and stuff, and (b) does it really matter to your
application?
This is good. I had thought about extracting the fields individually to a
stuct but by mentioning each one explicitly. I hadn't thought about stepping
a pointer along them. As long as the get16_le operations were fast I don't
think your method would be slow per se. I might use that type of code in
some cases. Objections to the code, though:
* It effectively uses magic numbers for the field offsets. Is that good
practice?
* In some cases not all fields would need to be converted. Details follow.
As an example of the latter, and to correct the layout I had before which
had the odd and even alignments the wrong way round, here is the full struct
for the structure in question. I have simplified the field names as the
standard ones were just too ucky!
/*
* Define the FAT geometry table at the start of a volume
*
* The numbers preceding each field give the byte offsets of that field.
* Fields which cannot be aligned are split into arrays of octets.
*/
struct bootsect {
/* 0 */ ui8 jump[3],
/* 3 */ ui8 oem[8],
/* 11 */ ui8 secsize[2], /* Split due to alignment */
/* 13 */ ui8 sec_per_clus,
/* 14 */ ui16 sec_rsvd,
/* 16 */ ui8 fats,
/* 17 */ ui8 rootents[2], /* Split due to alignment */
/* 19 */ ui8 totsec16[2], /* Split due to alignment */
/* 21 */ ui8 medium_type,
/* 22 */ ui16 fatsize16,
/* 24 */ ui16 sec_per_trk,
/* 26 */ ui16 heads,
/* 28 */ ui32 hid_sec,
/* 32 */ ui32 totsec32,
/* 36 */ ui8 drv_num,
/* 37 */ ui8 rsvd1,
/* 38 */ ui8 bootsig,
/* 39 */ ui8 volid[4], /* Split due to alignment */
/* 43 */ ui8 vollab[11],
/* 54 */ ui8 fstype[8]
/* 63 */
};
typedef struct bootsect bootsect_t;
As you can see, in this case and as long as I have got the layout right,
there should be only four fields which would have to be split due to
alignment issues. The other fields should be accessible directly and so not
need to be converted first.
James