Подтвердить что ты не робот

Visual С++ 2010: Почему "подписанное/неподписанное несоответствие" исчезает, если я добавляю "const" к одному сравнению?

У меня есть следующий простой код на С++:

#include "stdafx.h"
int main()
{
    int a = -10;
    unsigned int b = 10;
    //  Trivial error is placed here on purpose to trigger a warning.
    if( a < b ) {
        printf( "Error in line above: this will not be printed\n" );
    }
    return 0;
}

Скомпилированный с использованием Visual Studio 2010 (по умолчанию консольное приложение С++) дает warning C4018: '<' : signed/unsigned mismatch" on line 7 как ожидалось (код имеет логическую ошибку).

Но если я изменю unsigned int b = 10; на const unsigned int b = 10;, предупреждение исчезнет! Существуют ли какие-либо известные причины такого поведения? gcc показывает предупреждение независимо от const.

Обновление

Я вижу из комментариев, что многие люди предлагают "он как-то оптимизировался так, чтобы не было необходимости". К сожалению, требуется , так как в моем примере кода есть фактическая логическая ошибка, помещенная так, чтобы вызвать предупреждение: оператор print не будет называться, независимо от того, что -10 на самом деле меньше 10. Эта ошибка хорошо известна, и "предупреждение с подписью/без знака" точно выражается, чтобы найти такие ошибки.

Обновление

Я также вижу из комментариев, что многие люди "нашли" подписанную/неподписанную логическую ошибку в моем коде и объясняют это. Там, где это не нужно, эта ошибка помещается исключительно для запуска предупреждения, тривиальна (-10 проверяется на (unsigned int)-10, то есть 0xFFFFFFFF-10), и вопрос не в этом:).

4b9b3361

Ответ 1

Это ошибка Visual Studio, но пусть начнутся те аспекты, которые не являются ошибками.

Раздел 5, Примечание 9 затем применимый стандарт С++ вначале обсуждает, что делать, если операнды имеют разную ширину бита, прежде чем продолжить делать, если они одинаковы, но отличаются знаком:

... В противном случае, если операнд, который имеет целочисленный тип без знака, имеет ранг больше или равно рангам типа другого операнда, операнд со знаком целочисленного типа должен быть преобразован в тип операнд с целым числом без знака.

Здесь мы узнаем, что сравнение должно работать в беззнаковой арифметике. Теперь нам нужно узнать, что это значит для значения -10.

Раздел 4.6 сообщает нам:

Если тип назначения не указан, результирующее значение является наименьшим беззнаковое целое, совпадающее с целым числом источника (по модулю 2 n, где n - количество бит, используемых для представления неподписанного типа). [Примечание: в представление двойного дополнения, это преобразование является концептуальным и в битовой схеме нет изменений (если нет усечения). - end note] 3 Если тип назначения подписан, значение не изменяется если он может быть представлен в типе назначения (и ширине битового поля); в противном случае значение будет определено при реализации.

Как вы можете видеть, определенное довольно высокое значение (4294967286 или 0xFFFFFFF6, при условии, что unsigned int - это 32-разрядное число) сравнивается с 10, и поэтому стандарт гарантирует, что printf действительно никогда не вызывается.

Теперь вы можете мне поверить, что в этом стандарте нет правила, требующего диагностики, поэтому компилятор свободен не выпускать. (На самом деле, некоторые люди пишут -1 с целью создания шаблона бит all-ones. Другие используют int для итерации массивов, что приводит к сопоставлениям с подписью/без знака между size_t и int. Ужасно, но гарантировано для компиляции.)

Теперь Visual Studio выдает некоторые предупреждения "добровольно".

Это приводит к предупреждению уже по умолчанию (уровень 3):

int a = -10;
unsigned int b = 10;
if( a < b ) // C4018
{
    printf( "Error in line above: this will not be printed\n" );
}

Для получения предупреждения требуется /W4 следующее. Обратите внимание, что предупреждение было реклассифицировано. Он изменился с предупреждения C4018 на предупреждение C4245. Это, по-видимому, по дизайну. Логическая ошибка, которая почти всегда сравнивает сравнение, менее опасна, чем одна, которая работает с положительно-положительными сравнениями, но ломается с положительно-отрицательными.

const int a = -10;
unsigned int b = 10;
if( a < b ) // C4245
{
    printf( "Error in line above: this will not be printed\n" );
}

Но ваше дело было другим:

int a = -10;
const unsigned int b = 10;
if( a < b ) // no warning
{
    printf( "Error in line above: this will not be printed\n" );
}

И нет никакого предупреждения. (Ну, вы должны повторить с -Wall, если хотите быть уверенным.) Это ошибка. Microsoft говорит об этом:

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

Из любопытства я проверил с помощью Visual Studio 2012 SP1 и дефект все еще там - без предупреждения с -Wall.