RISC Machine Data Structure Word Alignment Problems?

John R. Levine johnl at esegue.segue.boston.ma.us
Mon Jan 22 09:48:26 AEST 1990


In article <111 at melpar.UUCP> toppin at melpar.UUCP (Doug Toppin   X2075) writes:
>We are using the SUN 4/260 which is a RISC architecture machine.
>We are having trouble with data alignment in our data structures.
>We have to communicate with external devices that require data structures
>such as the following:
>	struct
>	{
>		long  a;
>		short b;
>		long  c;
>	};

I guess all the world's not a Vax any more, now it's a 68020.  It would be
more correct to say that your external device requires a four-byte integer, a
two-byte integer, and a four-byte integer, all sent highest byte first.  C
makes no promise that the layout of structures will be the same from machine
to machine.  For instance, if you ran this code on a 386, there doesn't need
to be any padding (though many compilers add it to make the code run faster)
but the words are all in the opposite byte order.

The SPARC and every other RISC chip requires that items be aligned on their
natural boundaries, because there is considerable performance to be gained by
doing so, and because it is not very hard to write programs that are totally
insensitive to padding and byte order.  Many people have observed this.  In
an article on the IBM 370 series in the CACM about 10 years ago one of the
370's architects noted that the 370 permits misaligned data while its
predecessor the 360 didn't, and it was a mistake to have done so because it's
rarely used and adds considerable complicated to every 370 machine.

In the particular case of the SPARC, there is a C compiler option (documented
in the FM) to allow misaligned data at the enormous cost of several
instructions and sometimes a subroutine call for every load and store.  I
presume you are passing byte streams back and forth to your device, a memory
mapped interface that requires misaligned operands is too awful to
contemplate.  You need to write something like this:

read_foo_structure(struct foo *p)
{
	p->a = read_long();
	p->b = read_short();
	p->c = read_long();
}

long read_long(void)
{
	long v;

	/* read in big endian order */
	v = getc(f) << 24;	/* should do some error checking */
	v |= getc(f) << 16;
	v |= getc(f) << 8;
	v |= getc(f);
	return v;
}

This may seem like more work, but in my experience you write a few of these
things and use them all over the place.  Then your code is really portable.
-- 
John R. Levine, Segue Software, POB 349, Cambridge MA 02238, +1 617 864 9650
johnl at esegue.segue.boston.ma.us, {ima|lotus|spdcc}!esegue!johnl
"Now, we are all jelly doughnuts."



More information about the Comp.lang.c mailing list