Я написал этот макрос, чтобы получить битовую маску в общем:
#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 :
Результатом E1 << E2 является E1 сдвинутая влево позиция E2;освобожденные биты заполнены нулями.Если E1 имеет тип без знака, значение результата будет E1 x 2E2, уменьшенное по модулю на единицу больше, чем максимальное значение, представляемое в типе результата.Если E1 имеет тип со знаком и неотрицательное значение, а E1 x 2E2 представимо в типе результата, то это итоговое значение;в противном случае поведение не определено. </p>
результат, например, ((uint32_t)1)<<32
совершенно четко определен (чтобы быть +(uint32_t)0
), поэтому я думаю, что это немного странно, что совершенно четко определенная операция должнавыдает предупреждение при вызове компилятора, которое не запрашивает дополнительных предупреждений.