Есть ли предупреждение GCC, которое обнаруживает операции сдвига битов для подписанных типов?

Если я читаю спецификацию ISO C ++ (разделы 5.8.2 и 5.8.3) справа, сдвиг вправо с отрицательными знаковыми типами зависит от реализации, а поведение сдвига влево не определено.

Поэтому я хотел бы найти операции сдвига для подписанных типов в нашем унаследованном исходном коде, который мы компилируем с помощью g ++ 4.8.2.

К сожалению, я не смог найти такой вариант в руководство.
Я могу, например, скомпилировать этот код с «g ++ -Wall -Wextra -pedantic» без предупреждения:

int si    = -1;
int left  = si << 1; // -2 (multiplication by 2, sign is preserved)
int right = si >> 1; // -1 (no change, only 1s)

Может кто-нибудь сказать мне, если есть такое предупреждение, и если нет, почему gcc не заботится об этом?

13

Решение

насколько мне известно НКУ не предоставляет такую ​​возможность. Стандарт, как вы цитировали, гласит:

N3690 — §5.8.3

Значение E1 >> E2 — это биты E2, сдвинутые вправо E1. Если E1 имеет
тип без знака или если E1 имеет тип со знаком и неотрицательное значение,
значение результата является неотъемлемой частью отношения
E1 / 2E2. Если E1 имеет тип со знаком и отрицательное значение, результирующий
значение определяется реализацией.

а это значит делать

int si    = -1;
int right = si >> 1;

может или не может дать -1 в результате. Это реализация определена. И это означает компилятор не обязан выдавать предупреждение лайк «другие компиляторы могут сделать это по-другому».

Некоторые из причин этого выбора следуют.

Оригинал К&R отрывок говорит:

«Смещение вправо без знака, заполняет освобожденные биты 0. Право
сдвиг числа со знаком заполняется знаковыми битами (арифметическое смещение)
на некоторых машинах, таких как PDP-11, и с 0 битами (логический сдвиг)
на других. «

это означает, что операция зависит от архитектуры. Причиной этого является то, что некоторые архитектуры быстры в выполнении одного из двух, но не обоих.

Эта причина плюс тот факт, что полезность сдвигов с расширенными знаками является незначительной, заставило стандарт сделать выбор, оставив его «определенным для реализации». От «полезность знаковых расширенных смен«Я имею в виду, что смещение вправо арифметически целого числа со знаком минус не работает как положительный аналог (потому что потеря 1 справа уменьшает отрицательное число, то есть больше по модулю)

+63 >> 1 = +31 (integral part of quotient E1/2E2)
00111111 >> 1 = 00011111
-63 >> 1 = -32
11000001 >> 1 = 11100000

Рекомендации для дальнейшего чтения:

https://stackoverflow.com/a/1857965/1938163

http://www.ccsinfo.com/forum/viewtopic.php?t=45711

https://isocpp.org/std/the-standard


Редактировать: если вышеупомянутое не решает проблему (то есть код действителен, почему компилятор должен предупредить об этом?) Я предлагаю второе решение: AST matchers

Как описано здесь: http://eli.thegreenplace.net/2014/07/29/ast-matchers-and-clang-refactoring-tools/ Вы можете написать некоторый код, чтобы быстро идентифицировать все места с правыми сдвигами и со знаком в вашей программе.

Думайте об этом какнаписание моей небольшой проверки статического анализа одной задачи».


Изменить 2: вы также можете попробовать другие инструменты статического анализа, Clang имеет -fsanitize = сдвиг вариант, который может работать для вас. AFAIK также для НКУ они внедряли дезинфицирующее средство с неопределенным поведением, которое могло помочь диагностировать эти ошибки. Я не следил за историей, но я думаю, вы могли бы также попробовать.

6

Другие решения

Документация GCC Вот.

Похоже, что ответ «нет», нет никакого предупреждения о том, что вы хотите.

Я не знаю почему, но я предполагаю, что существует так много кода, который использует это, что было бы слишком шумно. C может не определять арифметические сдвиги, но в настоящее время практически все процессоры делают это одинаково, поэтому большинство людей считают, что оно определено именно так.

2

По вопросам рекламы [email protected]