This is slick. However, It would be a good idea to comment this line, for the -next- programmer to work on it.
–
mkClarkNov 25 '08 at 23:41

If this was coded as a function (the set_mask_n functions in @quinmar's answer), there'd be a one-line comment saying what the function does (and no argument 'k'), and users of the function would have the name as documentation. As a random expression in a bit of code, it would indubitably be BAD!
–
Jonathan LefflerNov 27 '08 at 5:55

2

The ~(~0 << m) is in paragraph 2.9 "Bitwise Operators" of "The C Programming Language, second edition" by Brian Kernighan and Dennis Ritchie. It is also in paragraph 7.5 "Space Efficiency" of "The Practice of Programming" by Brian W. Kernighan and Rob Pike.
–
Alessandro JacopsonJul 22 '11 at 6:57

Robert, I like the ~0 idiom for bitmasks because it doesn't depend on 2's-complement, and is in that sense simpler, but it's true it's less well-known. Just doing my bit to change that!
–
Darius BaconNov 25 '08 at 7:10

@Darius: if you are using unsigned arithmetic/types, as you should in these contexts, isn't the difference between 2's-complement, 1's-complement and sign-magnitude arithmetic immaterial?
–
Jonathan LefflerNov 25 '08 at 7:18

I like both solutions. Here is another way that comes to my mind (probably not better).

((~((unsigned int)0) << k) >> (k + n)) << n

EDIT:
There was a bug in my previous version (it was without the unsigned int cast). The problem was that ~0 >> n adds 1s at the front and not 0s.

And yes this approach has one big downside; it assumes that you know the number of bits of the default integer type or in other words it assumes that you really know k, whereas the other solutions are independent of k. This makes my version less portable, or at least harder to port. (It also uses 3 shifts, and addition and a bitwise negation operator, which is two extra operations.)

So you would do better to use one of the other examples.

Here is a little test app, done by Jonathan Leffler, to compare and verify the output of the different solutions:

On the assumption that this answer can be made to work, the obvious downside in comparison with the other two is the presence of the third shift operation, which makes it more time consuming.
–
Jonathan LefflerNov 25 '08 at 14:45

The other problem is that it uses the parameter k which the other two solutions are able to ignore (it doesn't use m, though, so it still only uses two of the three parameters).
–
Jonathan LefflerNov 25 '08 at 14:46

Right there was a bug in it, I fixed it now and add a comment that the other solutions are preferable. I haven't removed it completely, maybe someone can learn from my mistakes and it'd be sad to loose your nice test code :).
–
quinmarsNov 25 '08 at 19:34

Instead of the cast, you should be able to use '0U' to indicate an unsigned zero, or '0UL' to indicate an unsigned long. I agree with leaving your answer in place - and with the edits you made.
–
Jonathan LefflerNov 25 '08 at 21:06