Получить предупреждение о смещении влево отрицательного числа - PullRequest
1 голос
/ 29 июня 2019

Я пытаюсь сгенерировать предупреждение о неопределенном поведении при сдвиге влево отрицательного числа. Согласно этому ответу, сдвиг влево отрицательного числа в C не определен.

Результатом E1 << E2 является E1-сдвинутая влево позиция E2; освобожденные биты заполнены нулями. Если E1 имеет тип без знака, значение результата равно E1 × 2E2, уменьшенное по модулю на единицу больше, чем максимальное значение, представляемое в типе результата. Если E1 имеет тип со знаком и неотрицательное значение, а E1 × 2E2 представимо в типе результата, то это результирующее значение; в противном случае поведение не определено. </p>

Я пытаюсь понять, почему я не получаю предупреждение с этим кодом: x << 3

gcc -Wall (версия 9.1.0)

int main ()
{
    int x= -4, y, z=5;
    y = z << x;
    y = x << 3;
    return y;
}

На отдельной ноте меня также не предупреждают о сдвиге влево на отрицательное число z << x

Ответы [ 3 ]

1 голос
/ 30 июня 2019

В 5 << -4, как GCC 9.1.0, так и Apple LLVM 10.0.1 с clang-1001.0.46.4, нацеленный на x86-64, выдают предупреждающее сообщение («счет смещения влево отрицателен» для GCC и «счет смещения являетсяотрицательный »для LLVM-лязг).В -4 << 3 GCC не выдает предупреждение, а LLVM-clang («сдвиг отрицательного значения не определен»).

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

Когда операнд не являетсяконстанта, как в z << x и x << 3, мы можем предположить, что компилятор не видит операнд отрицательный, поэтому он не выдает предупреждение.Как правило, эти выражения могут иметь определенное поведение: если x не является отрицательным и находится в подходящих пределах (не превышает ширину z в первом случае и не настолько велико, что x << 3 переполняется во второмcase), поведение определено (исключая возможность переполнения z << x).Стандарт C не говорит, что сдвиги влево с типами, которые могут иметь отрицательные значения, т.е. , типы со знаком, не определены, просто что сдвиги влево с отрицательными значениями не определены.Следовательно, было бы ошибкой для компилятора выдавать предупреждающее сообщение всякий раз, когда x был подписанным типом в выражении, например z << x или x << 3.

Конечно, учитывая int x = -4 иотсутствие каких-либо изменений в x между этой инициализацией и выражениями z << x и x << 3, компилятор мог бы сделать вывод, что сдвиги не определены в этом конкретном случае, и выдать предупреждение.Это не требуется стандартом, и неспособность компилятора сделать это - просто вопрос качества реализации компилятора.

0 голосов
/ 30 июня 2019

Краткое объяснение того, что компилятор не выдает предупреждение в таких случаях, состоит в том, что это не требуется.

В определении «неопределенный» в стандарте также прямо говорится «не требуется никакой диагностики». Это означает, что стандарт не требует реализации для выдачи диагностики в таких случаях. Причиной этого является то, что технически компиляторы могут быть не в состоянии обнаружить все случаи неопределенного поведения в течение разумного времени или (в некоторых случаях) вообще. Некоторые случаи могут быть обнаружены только во время выполнения. Компиляторы являются сложными частями кода, поэтому, даже если человек может легко распознать проблему, компилятор не может (с другой стороны, компиляторы также обнаруживают проблемы, которые люди не могут легко найти).

Когда диагностика не требуется, есть несколько вещей - все на усмотрение - это должно произойти до того, как компилятор выдаст предупреждение.

Первое, что происходит, касается проблемы "качества реализации" - разработчик поставщика или компилятора решает написать код, который обнаруживает конкретные случаи, и другой код, который выдает предупреждение

Два шага (обнаружение случая и предупреждение о нем) являются отдельными и полностью дискреционными - стандарт не требует диагностики, поэтому даже если написан код, который обнаруживает конкретный случай, компилятору по-прежнему не требуется выдавать предупреждение об этом. Практически, даже если проблемы обнаружены, разработчики компилятора могут решить не выдавать предупреждение по различным причинам. Некоторые предупреждения касаются редких крайних случаев, поэтому не стоит прилагать усилия для их выдачи. Некоторые предупреждения имеют частоту «ложных срабатываний», что приводит к тому, что разработчики жалуются на сообщения об ошибках поставщику компилятора о ненужных предупреждениях - поэтому компилятор по умолчанию настроен так, чтобы они не излучали.

Следующим требованием для выдачи предупреждения является то, что пользователь компилятора должен выбрать отображение предупреждений. Благодаря активному лоббированию поставщиков разработчиками - большинство современных компиляторов настроены ПО УМОЛЧАНИЮ, поэтому они выдают только относительно небольшое количество предупреждений. Таким образом, разработчики, которые хотят получить как можно больше помощи от компилятора, должны явно включить его. Например, используя опции -Wall с gcc и clang.

0 голосов
/ 30 июня 2019

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

Чтобы не требовать, чтобы реализации вели себя не совсем идеально, авторы C99 решили разрешитьреализации для обработки таких случаев, однако они посчитали нужным.Вместо того, чтобы пытаться угадать во всех местах, где реализации могут иметь веские причины отклоняться от поведения C89, авторы Стандарта C99 предположительно ожидали, что реализации будут следовать поведению C89, отсутствует веская причина для иного , заставил ли Стандарт их сделать это или нет.

Если авторы стандарта намеревались внести какие-либо изменения в обработку операций левого сдвига в случаях, когда поведение C89 имело смысл следует упомянуть об изменении в опубликованном документе с обоснованием.Там нет ничего вообще.Единственный вывод, который я могу видеть из такого упущения, заключается в том, что переход от «Вести себя особым образом, который почти всегда имеет смысл», к «Вести себя таким образом, если разработчик считает, что это имеет смысл, и в противном случае обрабатывать код любым другим способом».мода, которую реализатор считает нужным, не рассматривалась как достаточное изменение, чтобы оправдать комментарий.Тот факт, что авторы Стандарта не смогли предписать поведение, никоим образом не означает, что они не ожидали, что реализации общего назначения с двумя дополнительными компонентами не будут продолжать обрабатывать такие сдвиги, как они всегда, и что программисты не должныиметь право на аналогичные ожидания.

...