Как я могу исправить такие предупреждения, как: «сравнение между подписанным и неподписанным»? - PullRequest
14 голосов
/ 13 мая 2009

Мне посоветовали использовать следующие опции с 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;

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

Ответы [ 8 ]

14 голосов
/ 13 мая 2009

Заменить

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

от

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

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

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

5 голосов
/ 13 мая 2009

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

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

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

2 голосов
/ 13 мая 2009

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

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

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

1 голос
/ 19 ноября 2015

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

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

0 голосов
/ 02 октября 2009

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

0 голосов
/ 13 мая 2009

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

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

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

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

0 голосов
/ 13 мая 2009

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

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

0 голосов
/ 13 мая 2009
test.c:11: error: comparison between signed and unsigned

Вы можете объявить x как целое число без знака, так как size_t без знака

РЕДАКТИРОВАТЬ:

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...