предупреждение компилятора: сдвиг влево отрицательного значения - PullRequest
0 голосов
/ 06 ноября 2019

Я думаю, что GCC неправильно выдает предупреждение [-Wshift-отрицательное значение].

У меня есть функция, которая должна создавать маску суффикса определенной длины, предоставляемую одним входным аргументом:

#include <stdint.h>

uint16_t get_suffix_mask_sht(uint8_t shift) {
    return (~(~((uint16_t) 0) << shift));
}

Я пытался скомпилировать эту функцию со следующими параметрами компилятора в разных версиях gcc

-Werror -Wextra

Это предупреждение также появляется, если я изменяю вывод с uint16_t на uint8_t. Большие типы вывода, например uint32_t, не выдают это предупреждение.

Я использую старую версию GCC: 7.4. Но я попробовал это на godbolt , используя последние версии GCC 9.x, и все они выдают одно и то же предупреждение. Однако версии Clang не выдают эту ошибку.

Ответы [ 2 ]

5 голосов
/ 06 ноября 2019

Когда переменные меньше int (например, uint16_t) используются с оператором побитового дополнения ~, они переводятся в int.

Тип int подписано, и не будет хорошо работать со сдвигом. Особенно с учетом того, что ~0 будет -1 с нотацией дополнения до двух (которая является наиболее распространенной нотацией для представления отрицательных чисел в двоичных системах).

Возможное решение заключается в использовании больших типов без знака (например, * 1014). *) и затем используйте маскирование, чтобы получить соответствующие биты для меньшего типа, когда закончите.

3 голосов
/ 06 ноября 2019

Предупреждение правильное.

~((uint16_t) 0) приводит к отрицательному значению, поскольку результат (uint16_t) 0 повышается до int перед выполнением побитового дополнения.

В целом, вы должны предпочестьцелые числа без знака (достаточно широкие, чтобы избежать продвижения типов) при использовании сдвига битов. Мое предложение было бы использовать unsigned int ноль вместо:

return (~(~0U << shift));
...