[comp.unix.programmer] struct 32 bit aligned and padded

stanonik@nprdc.navy.mil (Ron Stanonik) (04/11/91)

We ran into a little problem while porting some 4.3bsd/sunos
code to a 3b2 running sysVr3.2.  The problem was that on the
3b2, structs are not only aligned on 32 bit boundaries (which
we expected), but also padded to 32 bit boundaries.  For example,
here's a little program
	struct s0 { char c[2]; };

	struct s1 { struct s0 s0; short s; } x1;

	main()
	{
		printf("offset of short = %d\n", (int)&x1.s - (int)&x1);
	}

We expected the short x1.s to be two bytes from the start of the struct x1.
That's what happens on vax's running 4.3bsd, sun's running sunos4.1, hp's
running hpux, 386's running sysVr4.  But on the 3b2 running sysVr3.2,
x1.s is offset 4 bytes, apparently because the struct s0 is padded
out to a 32 bit boundary in s1.  Is this a "feature" of sysVr3.2,
or just the 3b2's?  From K&R second edition, I gather there are no
assurances regarding alignment or padding in this instance, but this
behaviour seems contrary to the usefulness of C as a low level language.

(Specfically we ran into this because EGP headers end on a 16 bit
boundary, immediately followed by the remainder of the EGP packet.
Because the header was padded, the remainder of the packet was
incorrectly positioned.)

Thanks,

Ron Stanonik
stanonik@nprdc.navy.mil
ucsd!nprdc!stanonik

chrisb@risky.Convergent.COM (Chris Bertin) (04/19/91)

In article <14082@arctic.nprdc.navy.mil> stanonik@nprdc.navy.mil (Ron Stanonik) writes:
...
alignment problem description deleted
...
>                  ... From K&R second edition, I gather there are no
>assurances regarding alignment or padding in this instance, but this
>behaviour seems contrary to the usefulness of C as a low level language.
>

If C had per-structure alignment directives, it would make it a lot more
useful as a low level language, but it would also make it a lot less portable.
Some compilers use environment variables (STALIGN, DBLALIGN in Motorola
compilers) to align structures. Perhaps the 3B2 has something of the sort.
This could help you in this case, although these variables may cause major
other problems if you end up with standard (/usr/include/...) structures
aligned differently between your .o files and the libraries.

-- 
Chris Bertin		|   chrisb@risky.Convergent.COM
Unisys			|		or
(408) 435-3762		| ...!uunet!pyramid!ctnews!risky!chrisb

stanonik@nprdc.navy.mil (Ron Stanonik) (04/20/91)

Alignment I can understand, but padding just seems like the
compiler writers got lazy.  It also meant that sizeof(struct packet)
wasn't the packet size, when the packet didn't end on a 32 bit boundary;
ie, we had to count up the bytes by hand to figure packet sizes.
We looked in vain for any cc flags that might disable padding,
but, as you said, we'd be wary of using such a flag for fear of
fouling up some sysV.3.2 include that expected the padding.
Did the 3b2 folks really use this compiler to compile the kernel;
ie, they didn't encounter any problems with this padding?

Thanks,

Ron Stanonik
stanonik@nprdc.navy.mil
ucsd!nprdc!stanonik

jim@segue.segue.com (Jim Balter) (04/21/91)

In article <14082@arctic.nprdc.navy.mil> stanonik@nprdc.navy.mil (Ron Stanonik) writes:
>The problem was that on the
>3b2, structs are not only aligned on 32 bit boundaries (which
>we expected), but also padded to 32 bit boundaries.

If a struct is aligned on a 32 bit boundary, that implies that it is padded
to a 32-bit boundary.  Consider struct foo x[2]; x[1] is aligned on a 32-bit
boundary.  Thus x[0] is padded to a 32-bit boundary.  If it weren't, then
sizeof(x) != sizeof(x[0]) + sizeof(x[1]).  If C had both a padd_sizeof and
an unpadded_sizeof, then this wouldn't need to be, but it doesn't.

>here's a little program
>	struct s0 { char c[2]; };
>
>	struct s1 { struct s0 s0; short s; } x1;
>
>	main()
>	{
>		printf("offset of short = %d\n", (int)&x1.s - (int)&x1);
>	}
>
>We expected the short x1.s to be two bytes from the start of the struct x1.

Some compilers are smart enough to align structures based on what they need.
Apparently, your 3b2 compiler is aligning all structures on 32-bit boundaries
even when they only need to be aligned on char boundaries.  A structure needs
to be as aligned as its most aligned member, but no more.  And there mustn't
be padding before the first member.  Thus, an s0 embedded in an s1 needs to be
short-aligned, but no more.

>But on the 3b2 running sysVr3.2,
>x1.s is offset 4 bytes, apparently because the struct s0 is padded
>out to a 32 bit boundary in s1.  Is this a "feature" of sysVr3.2,
>or just the 3b2's?

It's just a "feature" of the particular compiler you are using.

>From K&R second edition, I gather there are no
>assurances regarding alignment or padding in this instance, but this
>behaviour seems contrary to the usefulness of C as a low level language.

ANSI requires that an implementation document the alignment used, but it
can't mandate what that alignment is, precisely to make C useful as a low
level language, because different hardware has different requirements.
The expectation is that the alignment used suits the hardware, and that
structures are not more aligned than necessary.  You just happen to be using
a low-quality compiler.

If the structures you are dealing with are not being transmitted between
machines, there shouldn't be a problem unless there is some invalid use of
casts or unions.  If they are being transmitted between machines, they should
be converted to and from a canonical form.  Is is a mistake to make assumptions
about byte order or alignment consistency among different machine archtectures.