Подтвердить что ты не робот

Как я могу исправить предупреждения типа "сравнение между подписанным и неподписанным"?

Мне рекомендуется использовать следующие опции с GCC, так как это помогает избежать множества распространенных ошибок. Он включает кучу предупреждений и -Werror превращает их в ошибки.

gcc -pedantic -W -Wall -Wextra -Wshadow -Wstrict-overflow=5 -Wwrite-strings -std=c99 -Werror

Учитывая следующий тестовый код:

#include <stdio.h>

int main(void)
{
    int arr[8]={0,10,20,30,40,50,60,70};
    int x;

    printf("sizeof(arr): %d\n", sizeof(arr));
    printf("sizeof(int): %d\n", sizeof(int));

    for(x = 0; x < sizeof(arr)/sizeof(int); x++)
    {
        printf("%d\n",arr[x]);
    }

    return 0;
}

Я получаю это:

test.c:11: error: comparison between signed and unsigned

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

Другой способ - передать материал, но мне сказали, что кастинг устарел.

Кроме того, я мог бы сделать x в unsigned int:

unsigned x;

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

4b9b3361

Ответ 1

Это действительно зависит от типа данных. Этого можно избежать, неявным образом приведя значения к типу, который содержит надмножество всех значений, доступных в подписанном и неподписанном типе. Например, вы можете использовать 64-битное значение знака для сравнения 32-битного знака и знакового 32-битного значения.

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

Если вы должны бросить, подумайте, что вы можете вызвать переполнение и подумать, важно ли это для вашего приложения или нет.

Ответ 2

Заменить

int x;
/* ... */
for(x=0;x<sizeof(arr) / sizeof(int);x++)

по

for(size_t x=0;x<sizeof(arr) / sizeof(int);x++)

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

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

Ответ 3

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

Компилятор генерирует предупреждение, чтобы убедиться, что вы о них думаете. Использование -Werror способствует предупреждению об ошибке и остановке компиляции.

Будьте предельно осторожны в выборе соответствия вашим типам или отбросите проблему, если вы уверены, что она не применяется, или избавиться от -Werror и сделать ее политикой для устранения всех предупреждений с помощью исправления или объяснение...

Ответ 4

одним из вариантов будет дополнительный флаг "-Wno-sign-compare":)

Ответ 5

Одним из способов решения проблемы было бы выборочно отключить это предупреждение в этом специальном случае. GCC игнорирует диагностику pragma "-Wsomething"

// Disable a warning for a block of code:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
// ... Some code where the specified warning should be suppressed ...
#pragma GCC diagnostic pop

Последние версии GCC (на самом деле я не уверен, с тех пор, когда 4.8.x должен его поддерживать) покажите соответствующую опцию -Wsomething. Это важно, поскольку большинство параметров предупреждения не заданы явно, а en bloc с такими параметрами, как -Wall. Сообщение об ошибке будет выглядеть так:

readers.c: In function ‘buffered_fullread’:
readers.c:864:11: error: comparison between signed and unsigned integer expressions [-Werror=sign-compare]
    if(got < sizeof(readbuf)) /* That naturally catches got == 0, too. */

Часть [-Werror = sign-compare] сообщает вам. Вы можете использовать "Wsign-compare" для "Wsomething" для подавления предупреждения.

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

Ответ 6

test.c:11: error: comparison between signed and unsigned

Вы можете объявить x как unsigned int, так как size_t не имеет знака

ИЗМЕНИТЬ:

Если вы не хотите бросать и не хотите объявлять его как unsigned, я не думаю, что там что-то делать.

Возможно, побитовые операции - это способ его решения, удаляя бит знака. Я должен сказать, что ИМО очень сомнительна.

Ответ 7

Мы подавляем это предупреждение в наших компиляторах Visual Studio, поскольку это происходит много и почти никогда не означает ничего значительного. Конечно, не все стандарты кодирования позволяют это.

Вы можете согласовать типы (объявляя переменные как size_t или unsigned int вместо int, например), или вы можете использовать, или вы можете изменить свою линию компиляции. Что об этом.

Ответ 8

Независимо от дилеммы устаревания литья, я все же предлагаю отделить логику от цикла for.

int range = (int)(sizeof(arr) / sizeof(int));
int x;

for(x = 0; x < range; x++)
{
    printf("%d\n", arr[x]);
}

Хотя это использует литье, которое, как вы сказали, устарело, оно очищает место, где происходит кастинг. В общем, я советую не вводить много логики в ваши объявления цикла for. Особенно в вашем случае, когда вы используете разделение size_t, которое (поскольку это целочисленное деление) может иметь возможность усечения ответа. Объявление цикла цикла должно быть чистым и не должно генерировать ошибок. Ваше кастинг происходит в другом месте, что означает, что если вы хотите изменить способ создания диапазона, вам не нужно гадать, чтобы сделать объявление объявления еще длиннее.