В чем смысл этих сплетенных переменных предупреждений?
У меня есть такая функция:
#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);
}
Ответы
Ответ 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).
О том, почему вторая версия не выводит предупреждение... не знаю.