copx <co**@gazeta.plwrote:
How portable are direct bit operations? Which ones are portable?
I have never bothered learning such low-level stuff (I have an excuse: I am
not a professional programmer), so I really don't know.
You seem to be heading down the same, and wrong, path, that many
"professional" programmers have before you ;)
All operations, including bit operators, operate on the _logical_ values.
Lack of code portability is almost always an artifact of a programmer
forgetting or being ignorant of this fact (or maybe just asking for
trouble).
In C, almost by definition you never need (or should) care about how values
are represented in hardware. All you know is that you're given some
tools--operators and a language specification--that tell you how to
manipulate those values.
Bit operations required because you need to shuffle bytes based on
"little-endianness", etc, come from externalities. Even then, one only need
concern their self w/ the arrangement of the input, not w/ the destination
data object. Thus, if you somehow get a 4-byte "big-endian" from outside the
application, the following code is always portable:
/*
Filled from an fread() or some such mechanism. We're assuming
that each byte of data came in 4 8-bit units, and that our input
mechanism placed each 8-bit unit consecutively into one of the 4
array elements. Since it's "big-endian", the most signifiant byte
was read first, and is the first array element.
*/
unsigned char buf[4] = { 0x01, 0x00, 0x00, 0x00 };
unsigned long lu;
lu = ((unsigned long)buf[0] << (8 * 3))
| ((unsigned long)buf[1] << (8 * 2))
| ((unsigned long)buf[2] << (8 * 1))
| ((unsigned long)buf[3] << (8 * 0));
/*
This condition should _always_ be true, regardless of your platform.
Even if you're on one of the fabled DSP chips where (unsigned char)
is 16 bits.
*/
if (lu == 16777216) {
...
}
The mistake some programmers often make is to do something like the
following (note that I'm being generous, because their code is often much
more terse, assumes that CHAR_BIT is 8 w/o checking, and will often use
(unsigned long) assuming it to be 32-bits):
#include <stdint.h/* uint32_t */
#include <limits.h/* CHAR_BIT */
unsigned char srcbuf[4] = { 0x01, 0x00, 0x00, 0x00 };
unsigned char dstbuf[4];
uint32_t lu;
#if OUR_MACHINE_IS_LITTLE_ENDIAN
dstbuf[1] = srcbuf[3];
dstbuf[0] = srcbuf[2];
dstbuf[3] = srcbuf[1];
dstbuf[2] = srcbuf[0];
#else
(void)memcpy(dstbuf, srcbuf, sizeof dstbuf);
#endif
#if CHAR_BIT = 8
(void)memcpy(&lu, dstbuf, sizeof lu);
#else
#error Want CHAR_BIT to be 8
#endif