2010-09-07 2 views
49

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

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

Упражнение - В примере программы авторы используют 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).

+2

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

+0

Это правда, и я упомянул об этом в приведенном выше сообщении, но я до сих пор не понимаю, почему эта проблема не возникала в примерной программе автора, когда они использовали const int?Я уверен, что доберусь до этого в книге, но не могу не быть любопытным. –

+0

Лома, которая, очевидно, не давала предупреждения в этой ситуации, потому что int всегда будет 1 ... oops. –

ответ

65

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

Компиляторы предоставляют предупреждения о сравнении типов подписанных и неподписанных, поскольку диапазоны подписанных и неподписанных 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(); 
} 
+10

Я знаю, что в настоящем стандарте C иногда требуется, чтобы отрицательные значащие значения сравнивались больше, чем значения без знака, но должны ли какие-либо ситуации, когда это происходит, считаться устаревшими? Я бы хотел, чтобы стандарты эволюционировали, по крайней мере, для * разрешающих * компиляторов для создания арифметически-правильного поведения (что означает, что если подписанное значение отрицательно, оно сравнивается меньше, а если значение без знака превышает максимальное значение подписанного типа, сравнивается больше). Кажется странным, что компиляторы должны создавать дурацкое поведение в отсутствие явных приемов. – supercat

+3

@supercat: поскольку целочисленные сопоставления скомпилированы с одной машинной инструкцией, и для любой обработки или обработки кромки понадобится несколько машинных инструкций, то, что вы предлагаете, вряд ли будет добавлено как функция C ... это, конечно, не может быть поведение по умолчанию, так как оно без необходимости убивало бы производительность, даже если программист знает, что это необязательно. –

+0

@BlakeMiller: код, который хочет сравнить значение с подписью и без знака, как если бы оба они были без знака, может использовать один и запускать «полную скорость». В противном случае во многих случаях разница была бы между сравнением и прыжком с двумя инструкциями против трех, что было бы дешевле, чем код, который вручную обрабатывал различные случаи. – supercat

4

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

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

4

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

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

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

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

+0

А я вижу - теперь я изменил счетчик int как unsigned. Это считается хорошей практикой или даже плохой практикой? :) –

+0

Пожалуйста, если вы с трудом, коротко объясните почему. Даже если это только одно слово. Я не вижу ничего плохого в своем ответе. Что может быть проблемой, с которой вы можете мне помочь. – AndreasT

+1

@Tim: «unsigned» является синонимом «unsigned int». Вы должны использовать unsigned int или stl стандартный тип counting/iterating type std :: size_t (который также является синонимом). Лучше всего использовать unsigned во всех случаях «итерации по элементам от 0 до n». Он улучшает ясность и удаляет предупреждения, поэтому он является победителем ;-) – AndreasT

6

У меня была такая же проблема вчера, работая через проблему 2-3 в ускоренном 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 

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

0

или использовать this header library и написать:

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

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

Смежные вопросы