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

Предупреждение - сравнение между подписанными и беззнаковыми целыми выражениями

В настоящее время я работаю с помощью ускоренного С++ и сталкивался с проблемой в упражнении 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).

4b9b3361

Ответ 1

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

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

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

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

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

Что делает этот пример более сложным, так это то, что различные переменные padding (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 в микс, в любое время, когда вы хотите выполнить логическую операцию над этим элементом, все операнды должны иметь совместимый тип для компиляции без предупреждений.

Ответ 3

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

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

Ответ 4

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

0001 - 1 подпись и без знака 1001 - -1 и 9 без знака

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

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

Ответ 5

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

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

и не заботятся о подписанных/неподписанных или разных размерах

Ответ 6

Основная проблема заключается в том, что базовое оборудование, центральный процессор, имеет только инструкции для сравнения двух значений со знаком или сравнения двух значений без знака. Если вы передадите беззнаковой инструкции сравнения отрицательное значение со знаком, оно будет восприниматься как большое положительное число. Таким образом, -1, битовая комбинация со всеми битами (дополнение к двум), становится максимальным значением без знака для того же количества битов.

8 битов: -1 со знаком совпадает с 255 беззнаковыми 16-битными: -1 со знаком совпадает с 65535 без знака и т.д.

Итак, если у вас есть следующий код:

int fd;
fd = open( .... );

int cnt;
SomeType buf;

cnt = read( fd, &buf, sizeof(buf) );

if( cnt < sizeof(buf) ) {
    perror("read error");
}

вы обнаружите, что в случае сбоя вызова read (2) из-за того, что дескриптор файла стал недействительным (или из-за какой-либо другой ошибки), для этого cnt будет установлено значение -1. При сравнении с sizeof (buf), значением без знака, оператор if() будет ложным, поскольку 0xffffffff не меньше, чем sizeof() для некоторой (разумной, не придуманной, чтобы быть максимального размера) структуры данных.

Таким образом, вы должны написать выше, если, чтобы удалить подписанное/неподписанное предупреждение как:

if( cnt < 0 || (size_t)cnt < sizeof(buf) ) {
    perror("read error");
}

Это просто громко говорит о проблемах.

1.  Introduction of size_t and other datatypes was crafted to mostly work, 
    not engineered, with language changes, to be explicitly robust and 
    fool proof.
2.  Overall, C/C++ data types should just be signed, as Java correctly
    implemented.

Если у вас есть значения настолько большие, что вы не можете найти работающий тип значения со знаком, вы используете слишком маленький процессор или слишком большую величину значений на вашем языке. Если, как и в случае с деньгами, каждая цифра имеет значение, в большинстве языков есть системы, которые предоставляют вам бесконечные цифры точности. C/C++ просто не очень хорошо справляется, и вы должны быть очень откровенны во всем, что касается типов, как упоминалось во многих других ответах здесь.