在通用位掩码宏中静默-Wshift-count-overflow警告

时间:2018-11-07 18:10:19

标签: c gcc clang language-lawyer bit-shift

我写了这个宏以获取一般的位掩码:

#define BX_uint_least(Bits,Val) _Generic((char(*)[Bits]){0}, \
                                    char (*)[8]: (uint_least8_t)(Val), \
                                    char (*)[16]: (uint_least16_t)(Val), \
                                    char (*)[32]: (uint_least32_t)(Val), \
                                    char (*)[64]: (uint_least64_t)(Val))
#define BX_bitmask(Bits) ((BX_uint_least(Bits,1)<<Bits)-1)

但是当我使用它时,它会生成-Wshift-count-overflow条警告。

可以在宏内将这些警告静音吗?

我不想完全让他们沉默,因为,例如,UB造成 ((int32_t)1)<<32仍会收到警告,但是((uint_least32_t)1)<<32溢出到0完全是无害的和有意的。

示例程序:

#include <stdint.h>
#define BX_uint_least(Bits,Val) _Generic((char(*)[Bits]){0}, \
                                    char (*)[8]: (uint_least8_t)(Val), \
                                    char (*)[16]: (uint_least16_t)(Val), \
                                    char (*)[32]: (uint_least32_t)(Val), \
                                    char (*)[64]: (uint_least64_t)(Val))
#define BX_bitmask(Bits) ((BX_uint_least(Bits,1)<<Bits)-1)

int main() 
{

    //(void)((int32_t)1<<32); //UB; should warn
    (void)BX_bitmask(32); //shouldn't warn
    (void)(((uint32_t)1)<<32); //I don't care if it warns or not
}

顺便说一句,gcc和clang都发出了警告,而不必添加任何标志(例如-Wall-Wextra),但是通过阅读6.5.7p4:< / p>

  

E1 << E2的结果是E1左移E2位位置;空出   位填充零。如果E1具有无符号类型,则值   结果是E1 x 2E2,比最大值减少了1模   结果类型中可表示的值。如果E1具有带符号的类型,并且   非负值,并且E1 x 2E2在结果类型中可表示,   那就是结果值;否则,行为是   未定义。

例如((uint32_t)1)<<32的结果是定义明确的(将是+(uint32_t)0),因此我认为,定义良好的操作应该在编译器调用中省略警告,这有点怪异。 t要求额外的警告。

1 个答案:

答案 0 :(得分:2)

与类型的位大小相等的位移位为未定义

C standard states的第6.5.7p3节:

  

对每个操作数执行整数提升。的   结果的类型是提升后的左操作数的类型。 如果   右操作数的值是负数或大于   或等于提升的左操作数的宽度,其行为是   未定义。

因此,您不能安全地执行((uint_least32_t)1)<<32((uint32_t)1)<<32