colarat
colarat

Reputation: 33

In C, how to set first eight bits of any sized int in a generic way

How do I set the first (least significant) eight bits of any integer type to all zeroes? Essentially do a bitwise AND of any integer type with 0x00.

What I need is a generic solution that works on any integer size, but not have to create a mask setting all the higher bits to 1.

In other words:

0xffff             & 0x00 = 0xff00
0xaabbccddeeffffff & 0x00 = 0xaabbccddeeffff00

Upvotes: 2

Views: 1189

Answers (5)

KamilCuk
KamilCuk

Reputation: 140970

With bit shifts:

any_unsigned_integer = any_unsigned_integer >> 8 << 8;

Upvotes: 4

chqrlie
chqrlie

Reputation: 144695

The simplest solution works for all integer types on architectures with 2's complement representation for negative numbers:

val = val & ~0xff;

The reason is ~0xff evaluates to -256 with type int. Let's consider all possible types for val:

  • if the type of val is smaller than int, val is promoted to int, the mask operation works as expected and the result is converted back to the type of val.
  • if the type of val is signed, -256 is converted to type of val preserving its value, hence replicating the sign bit, and the mask is performed properly.
  • If the type of val is unsigned, converting -256 to this type produces the value TYPE_MAX + 1 - 256 that has all bits set except the 8 low bits, again the proper mask for the operation.

Another simple solution, that works for all representations of negative values is this:

val = val ^ (val & 0xff);

It requires storing the value into a variable to avoid multiple evaluation, whereas the first proposal can be applied to any expression with potential side-effects:

return my_function(a, b, c) & ~0xff;

Upvotes: 3

0___________
0___________

Reputation: 67476

Universal solution no mask, any number of bits

#define RESETB(val, nbits) ((val) ^ ((val) & ((1ULL << (nbits)) - 1)))

or even better

#define RESETB(val, nbits) ((val) ^ ((val) & ((nbits) ? ((nbits) >= sizeof(val) * CHAR_BIT ? ((1ULL << (sizeof(val) * CHAR_BIT)) - 1) : ((1ULL << (nbits)) - 1)) : 0)))

Upvotes: 0

paxdiablo
paxdiablo

Reputation: 881323

The C not operator ~ will invert all the bits of a given value so, in order to get a mask that will clear only the lower eight bits:

int val = 123456789;
int other_val = val & ~0xff; // AND with binary 1111 ... 1111 0000 0000
val &= ~0xff;                // alternative to change original variable.

If you have a wider (or thinner) type, the 0xff should be of the correct type, for example:

long val = 123456789L;
long other_val = val & ~(long)0xff;
val &= ~(long)0xff;          // alternative to change original variable.

Upvotes: 2

Ian Abbott
Ian Abbott

Reputation: 17403

One way to do it without a creating a mask for the higher bits is to use a combination of the & and ^ operators: x = x ^ (x & 0xFF); (or, using compound assignment: x ^= x & 0xFF;).

Upvotes: 1

Related Questions