2010-02-14 2 views
5

Несоблюдение подписанных/неподписанных несоответствий обязательно плохое?C89: несоответствие подписанного/неподписанного

Вот моя программа:

int main(int argc, char *argv[]) { 
    unsigned int i; 

    for (i = 1; i < argc; i++) { // signed/unsigned mismatch here 

    } 
} 

argc подписан, i нет. Это проблема?

+0

Не совсем обман, но стоит все равно прочитать: http://stackoverflow.com/questions/859943/c-how-can-i-fix-warnings-like-comparison-between-signed-and-unsigned – finnw

ответ

9

«Подписанные/неподписанные несоответствия» могут быть плохими. В вашем вопросе вы спрашиваете о сравнении. При сравнении двух значений одного и того же базового типа, но один подписанный и один без знака, подписанное значение преобразуется в unsigned. Так,

int i = -1; 
unsigned int j = 10; 

if (i < j) 
    printf("1\n"); 
else 
    printf("2\n"); 

печатает 2, а не 1. Это происходит потому, что в i < j, i преобразуется в unsigned int. (unsigned int)-1 равен UINT_MAX, очень много. Таким образом, условие оценивается как false, и вы попадаете в пункт else.

Для вашего конкретного примера argc гарантированно будет неотрицательным, поэтому вам не нужно беспокоиться о «несоответствии».

+0

Почему подписанный преобразован в unsigned (почему не наоборот)? это стандартизированное поведение? – triclosan

+0

@triclosan, да. Правила немного сложны, но для 'int' и' unsigned int', так как они имеют одинаковый ранг, подписанный тип преобразуется в неподписанный тип. См. Раздел 6.3.1.8 от N1256. –

1

Это не проблема в вашем конкретном случае, но компилятор не может знать, что у argc всегда будут значения, которые не вызовут никаких проблем.

+0

Если 'argc' слишком велик, чтобы вписаться в' int', у вас есть серьезные проблемы в любом случае :-) – finnw

+0

Не обязательно. «INT_MAX» может быть как 32767, и я видел командные строки, превышающие несколько сотен килобайт. Известно, что утилита xargs (1) легко достигает этого предела. – Jens

1

Это только косвенно проблема.

Плохие вещи могут случиться, если вы используете целые числа для битовых операций, таких как &, |, << и >>.
Совершенно разные плохие вещи могут произойти, если вы используете целые числа без знака для арифметических операций (опустошений, бесконечных циклов при испытании, если число >= 0 и т.д.)

Из-за этого некоторые компилятор и инструменты статической проверки будут выдавать предупреждения, когда вы смешиваете (арифметические или битовые манипуляции).

Несмотря на то, что это может быть безопасно смешать их в простых случаях, например, в вашем примере, если вы это сделаете, это означает, что вы не можете использовать эти статические средства проверки (или должен отключить эти предупреждения), что может означать, что другие ошибки не обнаружены.

Иногда у вас нет выбора, например. при выполнении арифметики по значениям типа size_t в коде управления памятью.

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

1

Неплохо. Я бы исправил предупреждения компилятора в отношении несоответствия подписанного/неподписанного, потому что могут произойти плохие вещи, даже если они маловероятны или невозможны. Когда вам нужно исправить ошибку из-за несоответствия подписанного/неподписанного, компилятор в основном говорит: «Я так сказал». Не игнорируйте предупреждение о нем по какой-то причине.

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

  • Нет связанных вопросов^_^