C
Chris Torek
(This is not quite right as stated, but I think I know what you
mean. However, there is nothing about "typedef" that makes any
difference here.)
Given:
struct bios_parameter_block { ... };
struct partition_boot_sector { ... };
(and no typedefs) I can rewrite what you have written as:
num_heads =
((struct bios_parameter_block *)
&(((struct partition_boot_sector *)&buf)->bpb))->number_of_heads;
though I would not write it like this, for a number of reasons.
Note that "&buf" is not needed here, because "buf" has type "array
512 of unsigned char", so that the "value" of buf falls under The
Rule and becomes a pointer to the first element of "buf". The
difference between &buf[0] and &buf is the type of the resulting
pointer.
If alignment and byte order are not concerns (i.e., if this code
is not intended to be portable), I would probably write:
struct partition_boot_sector *pbs;
struct bios_parameter_block *bpb;
...
pbs = (struct partition_boot_sector *)buf;
bpb = &pbs->bpb; /* (presumably this already has the right type) */
num_heads = bpb->number_of_heads;
If pbs->bpb does not have the correct type for some reason, the
second assignment would also need a cast.
Structure packing is of course not portable, so we should not even
mention it on comp.lang.c
mean. However, there is nothing about "typedef" that makes any
difference here.)
It could be used anywhere nested structures are used, such as a database.
But, let's work with two hard disk structures: 'partition boot sector' and
'bios parameter block' (which is part of the 'partition boot sector'). Say
you have a buffer, 'buf[512]', of unsigned char for reading sectors off the
hard disk. Now, you've read the partition boot sector off the hard disk
into your buffer. How do you get access data in the 'bios parameter block'
by name instead of by 'buf[x]'? You cast the buffer to a 'partition boot
sector'. From the 'partition boot sector', you get the offset of the 'bios
parameter block' which is then cast to a 'bios parameter block'. From the
casted 'bios parameter block', you get the data you need. For example, to
get the number of heads (FAT32X) (this is from working code) :
unsigned char buf[512];
//some disk read routine which gets the partition boot sector, not the
master boot sector
num_heads=((bios_parameter_block *)&(((partition_boot_sector
*)&buf)->bpb))->number_of_heads;
Given:
struct bios_parameter_block { ... };
struct partition_boot_sector { ... };
(and no typedefs) I can rewrite what you have written as:
num_heads =
((struct bios_parameter_block *)
&(((struct partition_boot_sector *)&buf)->bpb))->number_of_heads;
though I would not write it like this, for a number of reasons.
Note that "&buf" is not needed here, because "buf" has type "array
512 of unsigned char", so that the "value" of buf falls under The
Rule and becomes a pointer to the first element of "buf". The
difference between &buf[0] and &buf is the type of the resulting
pointer.
If alignment and byte order are not concerns (i.e., if this code
is not intended to be portable), I would probably write:
struct partition_boot_sector *pbs;
struct bios_parameter_block *bpb;
...
pbs = (struct partition_boot_sector *)buf;
bpb = &pbs->bpb; /* (presumably this already has the right type) */
num_heads = bpb->number_of_heads;
If pbs->bpb does not have the correct type for some reason, the
second assignment would also need a cast.
As long as the layout of the structures are correct (i.e., packed, if
necessary) ...
Structure packing is of course not portable, so we should not even
mention it on comp.lang.c