Легальное использование setjmp и GCC - PullRequest
2 голосов
/ 07 января 2011

Используя GCC (4.0 для меня), это законно:

if(__builtin_expect(setjmp(buf) != 0, 1))
  {
    // handle error
  }
else
  {
    // do action
  }

Я нашел дискуссию, в которой говорилось, что это создало проблему для GCC еще в 2003 году, но я думаю, что они уже исправили бы это. Стандарт C гласит, что использование setjmp незаконно, если только не выполняется одно из четырех условий, соответствующее условие:

  • один операнд реляционного оператора или оператора равенства с другим операндом целочисленное константное выражение, а результирующее выражение является полным управляющим выражением оператора выбора или итерации;

Но если это расширение GCC, могу ли я гарантировать, что оно будет работать для GCC, поскольку это уже нестандартная функциональность? Я проверил это, и это, казалось, сработало, хотя я не знаю, сколько тестов мне нужно было бы сделать, чтобы на самом деле сломать его. (Я скрываю вызов __builtin_expect за макросом, который определен как no-op для не-GCC, так что это будет совершенно законно для других компиляторов.)

Ответы [ 2 ]

0 голосов
/ 07 января 2011

Но если это расширение GCC, могу ли я гарантировать, что оно будет работать под GCC, поскольку это уже нестандартная функциональность? Я проверил это, и это, казалось, сработало, хотя я не знаю, сколько тестов мне нужно было бы сделать, чтобы на самом деле сломать его. (Я скрываю вызов __builtin_expect за макросом, который определен как no-op для не-GCC, поэтому это будет совершенно законно для других компиляторов.)

Вы правы, __builtin_expect должен быть макросом no-op для других компиляторов, поэтому результат все еще определен.

0 голосов
/ 07 января 2011

Я думаю, что стандарт говорил о том, чтобы сделать что-то вроде этого:

int x = printf("howdy");
if (setjmp(buf) != x ) {
    function_that_might_call_longjmp_with_x(buf, x);
} else {
    do_something_about_them_errors();
}

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

В своем коде вы могли бы написать это как:

int conditional;
conditional = setjump(buf) != 0 ;
if(__builtin_expect( conditional, 1)) {
    // handle error
} else {
    // do action
}

И я думаю, что мы можем убедиться, что строка кода, которая присваивает переменную conditional, отвечает этому требованию.

...