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

В чем смысл этих сплетенных переменных предупреждений?

У меня есть такая функция:

#include <setjmp.h>
jmp_buf buf;
void func2(int g);
extern int some_global;
void func(int x)
{
    if (setjmp(buf))
        return;
    if (some_global)
        x += 5;
    func2(x);
}

GCC (gcc (Debian 4.4.5-8) 4.4.5) дает предупреждение:

test.c: In function ‘func’:
test.c:5: warning: argument ‘x’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Wclobbered]

Почему???? Я имею в виду, очевидно, мне все равно, если x сбито или нет, потому что его нельзя использовать после возврата setjmp. Даже компилятор должен знать о чем-то столь ослепительно очевидном, учитывая, что он имеет какое-то особое знание setjmp.

Мой главный интерес - найти ошибки в базе кода, которую я унаследовал, поэтому "использовать этот стиль кодирования вместо" - это не совет, который я ищу. Однако здесь есть несколько странных поворотов. Например, если x является локальной переменной вместо параметра, то GCC не жалуется. Кроме того, GCC не будет жаловаться без строки if (some_global). Ницца. Что-то испортило анализ потока GCC, или, может быть, GCC знает то, чего я не знаю.

Итак,

  • Есть ли простой способ подавить это предупреждение для этой функции, точно так же, как вы можете использовать неиспользуемые параметры для (void)?

  • Или я просто подавляю предупреждение по всему проекту?

  • Или мне что-то не хватает?

Обновление: Позвольте мне поделиться с вами немного другой версией, которая не генерирует предупреждение:

#include <setjmp.h>
jmp_buf buf;
void func2(int g);
extern int some_global;
void func(int y)
{
    int x = y;
    if (setjmp(buf))
        return;
    if (some_global)
        x += 5;
    func2(x);
}
4b9b3361

Ответ 1

Немного соскабливая сеть и перечитывая документы GCC, я наткнулся на это:

Атрибуты функции:

returns_twice

Атрибут returns_twice сообщает компилятору, что функция может возвращаться более одного раза. Компилятор гарантирует, что все регистры будут мертвы, прежде чем вызывать такую ​​функцию, и выдаст предупреждение о переменных, которые могут быть сбиты после второго возврата из функции. Примерами таких функций являются setjmp и vfork. longjmp -подобный аналог такой функции, если таковой имеется, может быть отмечен атрибутом noreturn.

Итак, похоже, что GCC не имеет "специального знания" setjmp, он просто намекает, что это так. Все, что он знает, это то, что setjmp возвращается дважды, а не то, что он всегда возвращает 0 в первый раз и не равно нулю. Боже, это было бы хорошо.

Ответ 2

От man longjmp:

Значения автоматических переменных не указаны после вызова        longjmp(), если они отвечают всем следующим критериям:

   ·  they are local to the function that made the corresponding setjmp(3)
      call;

   ·  their  values  are  changed  between  the  calls  to  setjmp(3)  and
      longjmp(); and

   ·  they are not declared as volatile.

Как только ваша переменная x в первом примере соответствует критериям:

  • Он является локальным для функции, поскольку параметры функции аналогичны локальным автоматическим переменным.
  • Его значение может быть изменено сразу после setjmp, если some_global истинно.
  • Это не изменчиво.

Таким образом, его значение может быть неуказанным (clobbered).

О том, почему вторая версия не выводит предупреждение... не знаю.