Ответ 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
.