Предупреждение-сравнение между знаковыми и беззнаковыми целочисленными выражениями
В настоящее время я работаю над ускоренным C++ и столкнулся с проблемой в упражнении 2-3.
Краткий обзор программы - программа в основном берет имя, а затем отображает приветствие в рамке звездочек-то есть Привет ! окруженный обрамленными * ' s.
Упражнение - в примере программы авторы используют const int
для определения отступов (пробелов) между приветствием и звездочками. Затем они спрашивают читателя:, в рамках упражнения попросите пользователя ввести информацию о том, насколько большой должна быть прокладка.
Все это кажется достаточно простым, я иду вперед попросить пользователя для двух целых чисел (int
) и хранить их и изменить программу, чтобы использовать эти целые числа, удаляя те, которые используются автором, при компиляции, хотя я получаю следующее предупреждение;
Exercise2 в-3.cpp: 46: предупреждение: сравнение между знаковыми и беззнаковыми целочисленными выражениями
После некоторых исследований кажется, что потому что код пытается сравнить одно из приведенных выше целых чисел (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 ответов:
Обычно рекомендуется объявлять переменные как
Компиляторы предупреждают о необходимости сравнения подписанных и неподписанных типов, поскольку диапазоны подписанных и неподписанных int различны, и когда они сравниваются друг с другом, результаты могут быть удивительными. Если вы должны сделать такое для сравнения, вы должны явно преобразовать одно из значений в тип, совместимый с другим, возможно, после проверки, чтобы убедиться, что преобразование является допустимым. Например: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(); }
У меня была точно такая же проблема вчера, работая над проблемой 2-3 в ускоренном C++. Ключ состоит в том, чтобы изменить все переменные, которые вы будете сравнивать (используя булевы операторы) с совместимыми типами. В данном случае это означает
Обратите внимание, что в своем исходном коде они сделали именно это для счетчика c (страница 30 в разделе 2.5 книги), Как вы правильно указал.string::size_type
(илиunsigned int
, но поскольку в этом примере используется первый, я просто буду придерживаться этого, даже если эти два технически совместимы).Что делает этот пример более сложным, так это то, что различные переменные заполнения (paddides и paddopbottom), а также все счетчики, должнытакже быть изменены на
string::size_type
.Переходя к вашему примеру, код, который вы разместили, будет выглядеть следующим образом:
Обратите внимание, что в предыдущем условии вы получите ошибку, если не инициализируете переменную r как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
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
в смесь, каждый раз, когда вы хотите выполнить булеву операцию над этим элементом, все операнды должны иметь совместимый тип для компиляции без предупреждений.
Важное различие между знаковыми и беззнаковыми интами это интерпретация последнего бита. Последний бит в знаковых типах обозначают знак числа, означающий: например:
0001 - это 1 знак и без знака 1001 составляет -1 подписанные и неподписанные 9
(я избегал всей проблемы дополнения для ясности объяснения! Это не совсем то, как Инты представлены в памяти!)
Вы можете себе представить, что это имеет значение, чтобы знать, если вы сравниваете с -1 или с +9. Во многом бывает, программисты просто слишком ленивы объявить подсчет ints без знака (раздувание головки цикла for f. i.) Обычно это не проблема, потому что с ints вы должны считать до 2^31 пока твой знак не укусит тебя. Вот почему это только предупреждение. Потому что нам лень писать "unsigned" вместо "int".
В крайних диапазонах беззнаковый int может стать больше, чем int.
Поэтому компилятор выдает предупреждение. Если вы уверены, что это не проблема, не стесняйтесь приводить типы к одному типу, чтобы предупреждение исчезло (используйте приведение C++, чтобы их было легко обнаружить).В качестве альтернативы, сделайте переменные одного типа, чтобы остановить компилятор от жалоб.
Я имею в виду, возможно ли иметь отрицательную прокладку? Если да, то сохраните его как int. В противном случае вы должны вероятно, используйте unsigned int и позвольте потоку поймать ситуации, когда пользователь вводит отрицательное число.
Или используйте эту библиотеку заголовков и напишите:
// |notEqaul|less|lessEqual|greater|greaterEqual if(sweet::equal(valueA,valueB))
И не заботьтесь о подписанных/неподписанных или разных размерах