Почему сравнение, если Unsigned Int> = 0, «бессмысленное сравнение»? - PullRequest
19 голосов
/ 21 февраля 2011

Я получил предупреждение:

Pe186 "Бессмысленное сравнение беззнакового целого с нулем"

когда я пытался скомпилировать следующий код:

for(clLoop = cpLoopStart; clLoop >= 0; clLoop--)                                  
{
    //Do something
}

Я не понимаю, почему. Я мог бы понять, если бы я искал значение меньше ноль, так как unsigned int никогда не может быть отрицательным. Но все, что я ищу здесь, это если равно нулю, что, безусловно, может быть unsigned int.

Я мог бы даже увидеть эту ошибку, если бы в этом цикле я пытался выполнить предварительное уменьшение вместо последующего уменьшения, но, опять же, это не так.

Ответы [ 9 ]

45 голосов
/ 21 февраля 2011

Вы проверяете, больше ли unsigned int больше или равно (>=) нулю. Это выражение всегда будет истинным, потому что целые числа без знака никогда не будут меньше нуля.

Компилятор пытается предупредить вас, что вы собираетесь запрограммировать бесконечный цикл.

8 голосов
/ 21 февраля 2011

Вы проверяете, является ли целое число без знака равным или большим, чем 0. Что всегда верно.

4 голосов
/ 21 февраля 2011

Целое число без знака никогда не падает ниже 0 даже после бесконечного уменьшения (т. Е. clLoop >= 0 всегда будет истинным), что делает сравнение бессмысленным.

3 голосов
/ 21 февраля 2011

Я думаю, что вы хотели сказать

for(clLoop = cpLoopStart; clLoop; clLoop--)                                  
{ //Do something
}
2 голосов
/ 21 февраля 2011

clLoop >= 0 всегда верно.Неважно, пре-декремент вы или пост-декремент, значение без знака равно как минимум 0. Когда вы уменьшаете 0, вы получаете UINT_MAX.

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

1 голос
/ 22 июля 2017

do {} while () может помочь вам использовать переменные без знака для цикла без целочисленного переполнения:

// main.c
#include <stdio.h>

int main(void)
{

    int array[] = {1,2,3,4,5,6,7,8,9,10};
    unsigned int size = sizeof(array)/sizeof(int); // size == 10;

    unsigned int i = size;
    do
    {
        i--;
        printf("Index: %u, content: %d\n",i,array[i]);

    } while(i > 0);

    return 0;
}

и скомпилировать его с помощью:

gcc -std=c11 -Wall -Wextra -Wpedantic main.c

Вывод:

Index: 9, content: 10
Index: 8, content: 9
Index: 7, content: 8
Index: 6, content: 7
Index: 5, content: 6
Index: 4, content: 5
Index: 3, content: 4
Index: 2, content: 3
Index: 1, content: 2
Index: 0, content: 1
1 голос
/ 21 февраля 2011

Предупреждение жалуется на ваше for состояние разрыва контура clLoop >= 0. Цикл закончится, если clLoop станет отрицательным, но это никогда не произойдет для целого без знака.

0 голосов
/ 30 ноября 2018

Вы должны удалить = в

clLoop >= 0

Допустим, ваше cpLoopStart is 5.

Тогда значение clLoop в следующей итерации будет равно -

clLoop = 4;
clLoop = 3;
clLoop = 2;
clLoop = 1;
clLoop = 0;
clLoop = 0;
clLoop = 0;
clLoop = 0;
|
|
|
Infinite times.
0 голосов
/ 21 мая 2017

gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-11) в Centos 7 x86_64 не выдает предупреждение.

Но когда индекс цикла уменьшается до -1, индекс цикла неявно преобразуется в значение, равное UINT_MAX ( limit.h )

UINT_MAX + 1u is equal to 0,0 - 1 is equal to UINX_MAX.

limit.h Различные зависящие от платформы константы, предложенные ANSI

Одно из альтернативных решений:

unsigned int clLoop, i;

for(i = cpLoopStart+1, clLoop = i-1; i > 0; i--, clLoop = i-1)                                  
{
    //Do something
}

i изменится в диапазоне [1, cpLoopStart + 1]

clLoop изменится в диапазоне [0, cpLoopStart]

...