Portability vs. Endianness

John F. Woods jfw at ksr.com
Wed Mar 13 04:35:41 AEST 1991


esink at turia.dit.upm.es writes:
>Forgive me if this has been discussed to death (FMITHBDTD)

It probably has been, but perhaps what can be said about the answer will
be interesting:

>Given the following :
>long var;
>unsigned char Bytes[4];


>Is there a portable way to move the value held in var
>into the memory space pointed to by Bytes, with the restriction
>that the representation be in Most Significant Byte first
>format ?  I am well aware that sizeof(long) may not be 4.  I
>want the value contained in var converted to a 68000
>long word, and I want the code fragment to run on any
>machine.  The solution must be ANSI C.

	Bytes[0] = (var >> 24) & 0xFF;
	Bytes[1] = (var >> 16) & 0xFF;
	Bytes[2] = (var >> 8)  & 0xFF;
	Bytes[3] =  var        & 0xFF;

This code is guaranteed.

It might not be out of place to surround it with #ifdefs, so as to enable
more efficient code sequences to be used when possible:

#if defined(LONGS_ARE_4_BYTES) && defined(BIGENDIAN) && defined(LOOSEALIGN)
	/* eg 68020 */
	*(long *)Bytes = var;
#elif defined(LONGS_ARE_4_BYTES) && defined(BIGENDIAN)
	/* eg 68000; maybe Bytes can be an odd address */
	Bytes[0] = ((char *)&var)[0];
	Bytes[1] = ((char *)&var)[1];
	Bytes[2] = ((char *)&var)[2];
	Bytes[3] = ((char *)&var)[3];
#else
	Bytes[0] = (var >> 24) & 0xFF;
	Bytes[1] = (var >> 16) & 0xFF;
	Bytes[2] = (var >> 8)  & 0xFF;
	Bytes[3] =  var        & 0xFF;
#endif

Note that BIGENDIAN and LOOSEALIGN are *application defined* keywords here
that would be part of your configuration process; ANSI C does not mandate
any particular kind of compiler-provided help for this.  Considering the
subtleties that might interfere with these tricks even if "BIGENDIAN" and
"LOOSEALIGN" appear to be true, perhaps better defines might be something like
#ifdef TRICK666
	/* 68020 stuff */
#elif TRICK665
	/* 68000 stuff */
#else
	/* guaranteed stuff */
#endif

where your porting manual for your software package explains just what
TRICK665 and TRICK666 are, what constraints are involved, and points out
that the code is guaranteed to run correctly even if they are not defined
when they could be ("Make it right, then make it fast.").  You do write
porting manuals for your software packages, don't you?

One might also want to include the possibility (in the 68000 code) that
memcpy() is a compiler builtin which can be particularly efficient, but
this does seem like it's getting to be an awful lot of typing for relatively
little benefit.

Note that depending on WHY your application is copying longs into char[]
buffers, you might want the solution to look completely different, possibly
hidden behind a macro like "putlong()" (or "putint32()") which could then
expand into the above mess.



More information about the Comp.lang.c mailing list