Taylor
Taylor

Reputation: 555

set most significant bit in C

I am trying to set the most significant bit in a long long unsigned, x. To do that I am using this line of code:

x |= 1<<((sizeof(x)*8)-1);

I thought this should work, because sizeof gives size in bytes, so I multiplied by 8 and subtract one to set the final bit. Whenever I do that, the compiler has this warning: "warning: left shift count >= width of type"

I don't understand why this error is occurring.

Upvotes: 13

Views: 15484

Answers (4)

Ulli
Ulli

Reputation: 11

Thanks to the 2's complement representation of negative integers, the most-negative interger is exactly the desired bit pattern with only the MSB set. So x |= (unsigned long long )LONG_LONG_MIN; should work too.

Upvotes: 0

AnT stands with Russia
AnT stands with Russia

Reputation: 320481

The 1 that you are shifting is a constant of type int, which means that you are shifting an int value by sizeof(unsigned long long) * 8) - 1 bits. This shift can easily be more than the width of int, which is apparently what happened in your case.

If you want to obtain some bit-mask mask of unsigned long long type, you should start with an initial bit-mask of unsigned long long type, not of int type.

1ull << (sizeof(x) * CHAR_BIT) - 1

An arguably better way to build the same mask would be

~(-1ull >> 1)

or

~(~0ull >> 1)

Upvotes: 20

Artur
Artur

Reputation: 7257

use 1ULL << instead of 1 <<

Using just "1" makes you shift an integer. 1ULL will be an unsigned long long which is what you need. An integer will probably be 32 bits and long long probably 64 bits wide. So shifting:

1 << ((sizeof(long long)*8)-1)

will be (most probably):

1 << 63

Since 1 is an integer which is (most probably) 32 bits you get a warning because you are trying to shift past the MSB of a 32 bit value.

Upvotes: 7

Arkku
Arkku

Reputation: 42139

The literal 1 you are shifting is not automatically an unsigned long long (but an int) and thus does not have as many bits as you need. Suffix it with ULL (i.e., 1ULL), or cast it to unsigned long long before shifting to make it the correct type.

Also, to be a bit safer for strange platforms, replace 8 with CHAR_BIT. Note that this is still not necessarily the best way to set the most significant bit, see, e.g., this question for alternatives.

You should also consider using a type such as uint64_t if you're assuming unsigned long long to be a certain width, or uint_fast64_t/uint_least64_t if you need at least a certain width, or uintmax_t if you need the largest available type.

Upvotes: 1

Related Questions