GCC -Wuninitialized / -Wmaybe-неинициализированные проблемы

Я испытываю очень странную проблему, используя gcc-4.7 (Ubuntu/Linaro 4.7.2-11precise2) 4.7.2, Я не могу скомпилировать следующий действительный код без предупреждения:

extern void dostuff(void);

int test(int arg1, int arg2)
{
    int ret;

    if (arg1) ret = arg2 ? 1 : 2;

    dostuff();

    if (arg1) return ret;

    return 0;
}

Параметры компиляции и вывод:

$ gcc-4.7 -o test.o -c -Os test.c -Wall
test.c: In functiontest’:
test.c:5:6: warning: ‘ret’ may be used uninitialized in this function [-Wmaybe-uninitialized]

Однако следующий код компилируется без предупреждения (хотя и с несколько менее эффективной сборкой):

extern void dostuff(void);

int test(int arg1, int arg2)
{
    int ret;

    if (arg1 && arg2) ret = 1;
    if (arg1 && !arg2) ret = 2;

    dostuff();

    if (arg1) return ret;

    return 0;
}

Я немного застрял и рассматриваю это как ошибку компилятора. Какие-нибудь мысли?

2 ответа

Решение

На самом деле это известная проблема в gcc.
gcc известен тем, что сообщал о неверных неинициализированных переменных.
Недостатки были должным образом отмечены, и есть инициатива, чтобы преодолеть недостатки:
Лучшие неинициализированные предупреждения:

Коллекция компиляторов GNU предупреждает об использовании неинициализированных переменных с опцией -Wuninitialized, Тем не менее, текущая реализация имеет некоторые недостатки. С одной стороны, некоторые пользователи хотели бы получать более подробные и последовательные предупреждения. С другой стороны, некоторые пользователи хотели бы получать как можно меньше предупреждений. Цель этого проекта - реализовать обе возможности, одновременно улучшая текущие возможности.

Инициатива направлена ​​на предоставление более качественных предупреждений и приводит пример, аналогичный вашему. Соответствующая часть:

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

int x;
if (f ())
     x = 3;
return x;

где 'f' всегда возвращает ненулевое значение для текущей среды, и, таким образом, оно может быть оптимизировано. Здесь группа пользователей хотела бы получить неинициализированное предупреждение, поскольку "f" может возвращать ноль при компиляции в другом месте. Тем не менее, другая группа пользователей посчитает ложным предупреждение о ситуации, которая не может возникнуть в компилируемом исполняемом файле.

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

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

      int test(int arg1, int arg2)
{
    int ret;
    if (arg1) ret = arg2 ? 1 : 2;
    dostuff();
    if (arg1) return ret;
    return 0;
}

можно легко преобразовать в следующий код, просто объединив два идентичных if заявления в один:

      int test(int arg1, int arg2)
{
    if (arg1) {
        int ret = arg2 ? 1 : 2;
        dostuff();
        return ret;
    }
    dostuff();
    return 0;
}

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

Но опять же, код можно еще больше упростить:

      int test(int arg1, int arg2)
{
    dostuff();
    return (arg1 ? (arg2 ? 1 : 2) : 0);
}

Задача решена, ret ушел.

Другие вопросы по тегам