2011-12-19 6 views
5

Когда я пытаюсь скомпилировать следующую программу на C++ с использованием компилятора Visual Studio 2010 C++ (X86) с включенным уровнем предупреждения/W4, я получаю предупреждение о несоответствии с подписью/без знака на отмеченная строка.C++: несоответствие подписи/без знака при использовании неподписанных типов

#include <cstdio> 
#include <cstdint> 
#include <cstddef> 

int main(int argc, char **argv) 
{ 
    size_t idx = 42; 
    uint8_t bytesCount = 20; 

    // warning C4389: '==' : signed/unsigned mismatch 
    if (bytesCount + 1 == idx) 
    { 
     printf("Hello World\n"); 
    } 

    // no warning 
    if (bytesCount == idx) 
    { 
     printf("Hello World\n"); 
    } 
} 

Это меня смущает, поскольку я использую только неподписанные типы. Поскольку сравнение

bytesCount == idx 

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

Таким образом: по какой причине я получаю это предупреждение и по каким правилам происходит этот разговор (если это причина)?

ответ

5

1 является int. Тип интегрального арифметического выражения зависит от используемых типов. В этом случае у вас есть тип unsigned и тип signed, где тип unsigned меньше, чем у signed. Это подпадает под стандартом С ++ на выражениях (раздел 5.10 [выражение]):

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

т.е. тип выражения bytesCount + 1 является int, который подписывается по умолчанию.

9

1 - подписанный литерал. Попробуйте bytesCount + 1U.

Компилятор, вероятно, создает временное значение подписанного типа за счет добавления знаковых и беззнаковых значений (bytesCount + 1)

3

С 1 имеет тип int выражение bytesCount + 1 является int (подпись).

В самом деле, когда тип меньше int используется в математическом выражении он повышен до int, так что даже + bytesCount и bytesCount + bytesCount считаются int и не uint8_t (в то время как bytesCount + 1U является unsigned int, так что больше, чем int) ,

following program выходы true три раза.

#include <iostream> 

int main() 
{ 
    unsigned short s = 1; 
    std::cout << (&typeid(s + 1U) == &typeid(1U)) << std::endl; 
    std::cout << (&typeid(+ s) == &typeid(1)) << std::endl; 
    std::cout << (&typeid(s + s) == &typeid(1)) << std::endl; 
} 
1

Другие ответы уже говорят вам, что bytesCount + 1 интерпретируется как signed int. Тем не менее, я хотел бы добавить, что в bytesCount == idx, bytesCount is также интерпретирован как signed int. Концептуально он сначала преобразуется в signed int, и после этого он преобразуется только в unsigned int. Ваш компилятор не предупреждает об этом, потому что у него достаточно информации, чтобы знать, что на самом деле нет проблем. Преобразование в signed int не может сделать bytesCount отрицательным.Сравнение bytesCount + 1 одинаково справедливо, равномерно безопасно, но просто немного сложнее, чтобы компилятор больше не считал его безопасным.

+0

И как сообщить компилятору, чтобы он не предупреждал меня о такой проблеме, если из кода программы видно, что сравнение безопасно, но я не хочу отключать предупреждения для всего файла, и я не хочу делать код уродливым чтобы избежать этого. Существуют ли какие-либо способы достижения этого? – Arkady

+0

@Arkady Если компилятор настроен на предупреждение для кода, вы не хотите менять код (потому что он будет более уродливым), и вы не хотите изменять конфигурацию компилятора (потому что он будет подавлять полезные предупреждения тоже), вы не оставляете много вариантов открытыми. Единственный вариант, о котором я могу думать, что вы еще не исключили, - это взломать компилятор, чтобы улучшить его анализ. – hvd