Отключение предупреждения -Wshift-count-overflow в универсальном макросе битовой маски - PullRequest
0 голосов
/ 07 ноября 2018

Я написал этот макрос, чтобы получить битовую маску в общем:

#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), поэтому я думаю, что это немного странно, что совершенно четко определенная операция должнавыдает предупреждение при вызове компилятора, которое не запрашивает дополнительных предупреждений.

1 Ответ

0 голосов
/ 07 ноября 2018

Сдвиг битов на величину, равную размеру бита типа: undefined .

Раздел 6.5.7p3 стандартных состояний C :

Целочисленные продвижения выполняются для каждого из операндов. тип результата - тип повышенного левого операнда. Если значение правого операнда отрицательно или больше или равна ширине повышенного левого операнда, поведение не определено.

То есть вы не можете безопасно выполнить ((uint_least32_t)1)<<32 или ((uint32_t)1)<<32.

...