Mask calculation macro

We have a bunch of C macros here for using the preprocessor to perform operations on bit fields, and we fire warnings when trying to use those macros in visual studio. The problem can be demonstrated very easily:

#define BITFIELD_WIDTHMASK(Width) \
    ((Width) >= 32 ? ~0x0ul : (1ul << (Width)) - 1)

unsigned long foo(void)
{
    return BITFIELD_WIDTHMASK(32);
}

      

Compiling this with MSVC gives a warning:

test.c(12) : warning C4293: '<<' : shift count negative or too big, undefined behavior

      

This is not a behavior issue - the operator <<

will not be used in this case and must be detected at compile time. But are there any suggestions on how to rewrite the macro to avoid the warning? Or, otherwise, how to redesign the macro interface for this?

Thanks in advance

+2


a source to share


3 answers


What about:

#define BITFIELD_WIDTHMASK(Width) \
    ((Width) >= 32 ? ~0x0ul : (1ul << (Width % 32)) - 1)

      



?

+3


a source


#define BITFIELD_WIDTHMASK(Width) (((0x80000000ul >> (32-Width)) << 1) - 1)

      

Or handle width 0 as well as requested ...



#define BITFIELD_WIDTHMASK(Width) \
  ((Width) >= 32 \
  ? ~0x0ul \
  : (((1ul << ((Width)/2)) << ((Width)/2)) << ((Width)&1)) - 1)

      

+3


a source


The preprocessor, not the compiler, evaluates the expression when Width is a literal constant, and it is too dumb not to evaluate both sides of the?: Expression. I guess because it doesn't handle it at all, but rather inserts an expression ?: With constant operands!

If zero width is not required, the following simplification, which works from 1 to 32:

#define BITFIELD_WIDTHMASK(Width) (~0ul >> (32-(Width)))

      

It seems to me that if you know the width is zero (perhaps to turn off the feature), which is implicit if you are using a constant with a constant value, it would be wise to just use zero and not reference the macro.

+1


a source







All Articles