在通用位掩码宏中消除 -Wshift-count-overflow 警告
Silencing a -Wshift-count-overflow warning in a generic bitmask macro
我写了这个宏来获得一个通用的位掩码:
#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 的阅读:
The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated
bits are filled with zeros. If E1 has an unsigned type, the value of
the result is E1 x 2E2 , reduced modulo one more than the maximum
value representable in the result type. If E1 has a signed type and
nonnegative value, and E1 x 2E2 is representable in the result type,
then that is the resulting value; otherwise, the behavior is
undefined.
例如 ((uint32_t)1)<<32
的结果是完全明确定义的(成为 +(uint32_t)0
)所以我认为一个完全明确定义的操作应该在编译器调用中引发警告有点奇怪不要求额外的警告。
移位等于类型位大小的量是未定义。
C standard states 的第 6.5.7p3 节:
The integer promotions are performed on each of the operands. The
type of the result is that of the promoted left operand. If
the value of the right operand is negative or is greater than
or equal to the width of the promoted left operand, the behavior is
undefined.
所以你不能安全地执行((uint_least32_t)1)<<32
或((uint32_t)1)<<32
。
我写了这个宏来获得一个通用的位掩码:
#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 的阅读:
The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 x 2E2 , reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 x 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
例如 ((uint32_t)1)<<32
的结果是完全明确定义的(成为 +(uint32_t)0
)所以我认为一个完全明确定义的操作应该在编译器调用中引发警告有点奇怪不要求额外的警告。
移位等于类型位大小的量是未定义。
C standard states 的第 6.5.7p3 节:
The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand. If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.
所以你不能安全地执行((uint_least32_t)1)<<32
或((uint32_t)1)<<32
。