Path: utzoo!news-server.csri.toronto.edu!rutgers!cs.utexas.edu!uunet!ksr!jfw From: jfw@ksr.com (John F. Woods) Newsgroups: comp.lang.c Subject: Re: Portability vs. Endianness Message-ID: <2628@ksr.com> Date: 12 Mar 91 18:35:41 GMT References: <1991Mar12.105451.19488@dit.upm.es> Sender: news@ksr.com Lines: 73 esink@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.