From: jos@and.nl (Jos Horsmeier)
Newsgroups: comp.lang.c
Subject: Re: Question about fread() and fwrite()!
Date: 16 Oct 92 11:57:08 GMT
Organization: AND Software BV Rotterdam

In article <chupchup.719226774@piggy> chupchup@ferkel.ucsb.edu (Robert Earl) writes:
|ren@miles.mps.ohio-state.edu (Liming Ren) writes:

|| Another question is: Is the size of a structure the summation of all
|| the size of its elements? If not, any formula for it beside using
|| sizeof()?
|
|Yes, it is the sum of all the elements' sizes.

Sorry, it's not; its size is _at least_ the sum of the sizes of the elements.
A lot of processor architectures can't access all sorts of data types
on every possible memory location, e.g. my SPARC processor can only
access longs (4 bytes) on four byte address boundaries. Have a look at the
following snippet of code:

struct foo_struct { char foo; long bar; char boo; } *baz;
baz= malloc(2*sizeof(foo_struct));

Now, the baz pointer points to a memory location, suitably alligned to
store two foo_structs. The memory locations baz+1, baz+2, baz+3, baz+4
cannot contain a long (it would result in a so called `bus error' on 
my machine if I tried to store a long there.) The first three bytes are
simply wasted; they're alignment bytes. The long _can_ be stored at 
location baz+4 (it's a four byte boundary.) The first part of the
structure looks like this:

+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| foo | aln | aln | aln | bar | bar | bar | bar | boo |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+
   0     1     2     3     4     5     6     7     8

But things are even worse: just imagine what would happen if we
would dereference baz+1, i.e. if baz+1 would be pointing nine bytes
further up in memory. The next bar element would be located at
location baz+13, which definitely is _not_ a four bye address
boundary. That's where the padding bytes come in:

+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| foo | aln | aln | aln | bar | bar | bar | bar | boo | pad | pad | pad |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
   0     1     2     3     4     5     6     7     8     9    10    11

These padding bytes are needed to guarantee that any following struct
is located at a similar address boundary as the first one. 

So, this structure contains six useful bytes, three internal alignment
bytes and three pasdding bytes, making up a size of twelve bytes: a
wasting 50%! Sometimes it pays to think a bit `machine dependent',
rearranging the structure as:

struct foo_struct { long bar; char foo; char boo; } * baz;

would result in a memory layout like this:

+-----+-----+-----+-----+-----+-----+-----+-----+
| bar | bar | bar | bar | foo | boo | pad | pad |
+-----+-----+-----+-----+-----+-----+-----+-----+
   0     1     2     3     4     5     6     7   

Saving four bytes, (which isn't _that_ much, but imagine you have to
store a million of them ...) Concluding: structures can be bigger 
than you think they are and if you don't want to use the sizeof
operator, you cannot calculate the size of a structure in a machine
independent way.

Does this clarify things a bit?

kind regards,

Jos aka jos@and.nl
Newsgroups: comp.lang.c