Предупреждение - сравнение между целочисленными выражениями со знаком и без знака - PullRequest
60 голосов
/ 07 сентября 2010

Я сейчас работаю через Ускоренный C ++ и столкнулся с проблемой в упражнении 2-3.

Краткий обзор программы - программа в основномпринимает имя, затем отображает приветствие в рамке звездочек - т.е. Hello!окружен рамкой * х.

Упражнение - В примере программы авторы используют const int для определения отступов (пробелов) между приветствием и звездочками.Затем они просят читателя, как часть упражнения, попросить пользователя ввести информацию о том, насколько велики они хотят, чтобы отступ был.

Все это кажется достаточно простым, я продолжаю спрашивать у пользователя два целых числа(int) и сохраните их и измените программу на использование этих целых чисел, удаляя те, которые использовались автором, при компиляции, хотя я получаю следующее предупреждение:

Exercise2-3.cpp: 46: warning: сравнение между целочисленными выражениями со знаком и без знака

После некоторых исследований это происходит потому, что код пытается сравнить одно из указанных выше целых чисел (int) с string::size_type, чтохорошо.Но мне было интересно - значит ли это, что я должен изменить одно из целых чисел на unsigned int?Важно ли явно указать, являются ли мои целые числа знаковыми или беззнаковыми?

 cout << "Please enter the size of the frame between top and bottom you would like ";
 int padtopbottom;
 cin >> padtopbottom;

 cout << "Please enter size of the frame from each side you would like: ";
 unsigned int padsides; 
 cin >> padsides;

 string::size_type c = 0; // definition of c in the program
 if (r == padtopbottom + 1 && c == padsides + 1) { // where the error occurs

Выше приведены соответствующие биты кода, c имеет тип string::size_type, потому что мы не знаем, как долго может длиться приветствие - но почему я получаю эту проблему сейчас, когдаКод автора не получил проблему при использовании const int?Кроме того - всем, кто, возможно, выполнил Ускоренный C ++ - это будет объяснено позже в книге?

Я на Linux Mint использую g ++ через Geany, если это помогает или имеет значение(как я читал, что это может при определении того, что string::size_type).

Ответы [ 5 ]

84 голосов
/ 07 сентября 2010

Обычно хорошей идеей является объявление переменных как unsigned или size_t, если они будут сравниваться с размерами, чтобы избежать этой проблемы. По возможности используйте точный тип, с которым вы будете сравнивать (например, используйте std::string::size_type при сравнении с длиной std::string).

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

unsigned u = GetSomeUnsignedValue();
int i = GetSomeSignedValue();

if (i >= 0)
{
    // i is nonnegative, so it is safe to cast to unsigned value
    if ((unsigned)i >= u)
        iIsGreaterThanOrEqualToU();
    else
        iIsLessThanU();
}
else
{
    iIsNegative();
}
7 голосов
/ 07 января 2014

Вчера у меня была точно такая же проблема, работая над проблемой 2-3 в Accelerated C ++.Ключ заключается в том, чтобы изменить все переменные, которые вы будете сравнивать (используя логические операторы), на совместимые типы.В данном случае это означает string::size_type (или unsigned int, но, поскольку в этом примере используется первый, я просто буду придерживаться этого, даже если оба они технически совместимы).

Обратите внимание, что в исходном коде они сделали именно это для счетчика c (стр. 30 в разделе 2.5 книги), как вы правильно отметили.

Что делает этот пример более сложным, так эточто различные переменные заполнения (padsides и padtopbottom), а также все счетчики должны быть и изменены на string::size_type.

Возвращаясь к вашему примеру, код, который вы разместили, будет выглядеть примерно так:

cout << "Please enter the size of the frame between top and bottom";
string::size_type padtopbottom;
cin >> padtopbottom;

cout << "Please enter size of the frame from each side you would like: ";
string::size_type padsides; 
cin >> padsides;

string::size_type c = 0; // definition of c in the program

if (r == padtopbottom + 1 && c == padsides + 1) { // where the error no longer occurs

Обратите внимание, что в предыдущем условном выражении вы получите ошибку, если не инициализируетепеременная r как string::size_type в цикле for.Таким образом, вам нужно инициализировать цикл for, используя что-то вроде:

    for (string::size_type r=0; r!=rows; ++r)   //If r and rows are string::size_type, no error!

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

4 голосов
/ 07 сентября 2010

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

0001 - 1 со знаком, а без знака - 1001 - со знаком -1 и 9 без знака

(я избежал проблемы всего дополнениядля ясности объяснения! Это не совсем то, как целые числа представлены в памяти!)

Вы можете себе представить, что важно знать, сравниваете ли вы с -1 или с +9.Во многих случаях программистам просто лень объявлять подсчет целых чисел беззнаковым (вздутие fi заголовка цикла for). Обычно это не проблема, потому что с целыми числами нужно считать до 2 ^ 31, пока ваш знаковый бит не укусит вас.Вот почему это только предупреждение.Потому что нам лень писать «unsigned» вместо «int».

4 голосов
/ 07 сентября 2010

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

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

0 голосов
/ 09 апреля 2015

или используйте эту библиотеку заголовков и напишите:

// |notEqaul|less|lessEqual|greater|greaterEqual
if(sweet::equal(valueA,valueB))

и не заботитесь о знаках / без знака или других размерах

...