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

StackOverflow https://stackoverflow.com/questions/3660901

  •  01-10-2019
  •  | 
  •  

Вопрос

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

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

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

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

Упражнение2-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 ++ - Будет ли это объяснить позже в книге?

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

Это было полезно?

Решение

Обычно это хорошая идея объявить переменные как 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 ++. Ключ состоит в том, чтобы изменить все переменные, которые вы будете сравнивать (используя логические операторы) для совместимых типов. В этом случае это означает string::size_type (или unsigned int, Но поскольку этот пример использует первое, я просто придерживаюсь этого, хотя двое технически совместимы).

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

Что делает этот пример более сложным, состоит в том, что различные переменные прокладки (падуиды и падтопботтом), а также все счетчики, должны также быть измененным на 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 (string::size_type r=0; r!=rows; ++r)   //If r and rows are string::size_type, no error!

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

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

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

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

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

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

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

или использовать Эта библиотека заголовка и написать:

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

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

Основной проблемой является то, что основное оборудование, процессор, имеет только инструкции для сравнения двух подписанных значений или сравнить два значения без знака. Если вы проходите подписанное, отрицательное значение, если вы передаете подписанное, отрицательное значение сравнения, он будет относиться к нему как большое положительное число. Итак, -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");
}

Вы найдете, что если вызов чтения (2) не удается из-за дескриптора файла, станут недействительным (или какой-либо другой ошибкой), что CNT будет установлен на -1. При сравнении с SizeOf (Buf) значение unsigned, оператор IF () будет ложным, потому что 0xFFFFFFFFFFFFFFFFFF не меньше, чем 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 ++ просто не делают этого хорошо, и вы должны быть очень явны обо всем, что вокруг типов, как упоминалось во многих других ответах здесь.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top