我写了这个宏以获取一般的位掩码:
#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要求额外的警告。
答案 0 :(得分:2)
与类型的位大小相等的位移位为未定义。
C standard states的第6.5.7p3节:
对每个操作数执行整数提升。的 结果的类型是提升后的左操作数的类型。 如果 右操作数的值是负数或大于 或等于提升的左操作数的宽度,其行为是 未定义。
因此,您不能安全地执行((uint_least32_t)1)<<32
或((uint32_t)1)<<32
。