2011-01-07 3 views
2

Использование GCC (4.0 для меня), это юридический:Юридические использования setjmp и GCC

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

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

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

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

+0

Вам действительно нужен '__builtin_expect'? Я ожидал бы, что GCC будет рассматривать «setjmp» как особый случай и оптимизировать общий путь. Очень мало случаев появления этого шаблона в кодах google: http://google.com/codesearch?hl=ru&lr=&q=(__builtin_expect|likely).setjmp&sbtn=Search –

+0

@Giuseppe - Наверное, нет, но всегда хорошо учиться , –

+1

Весь '__builtin_expect' - смешная преждевременная оптимизация, которая убирает код для сомнительной выгоды. Если gcc имеет встроенный 'setjmp', он может даже оптимизировать весь условный код, указав, что' setjmp' сохраняет адрес иначе-недостижимого кода для ненулевого условия в буфере перехода напрямую, поэтому я думаю, что мы действительно имеем дело с Преждевременным Оптимизация считается вредной здесь. –

ответ

0

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

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, отвечает этому требованию.

+0

На самом деле даже ваша вторая не определена. Вы должны объявить условную неустойчивость для этого (чтобы запретить оптимизацию регистров). – Joshua

+0

@ Joshua: О чем ты говоришь? Значение, возвращаемое 'setjmp', является регулярным целым числом и не требует особой осторожности. Остальная часть программы нуждается в особой заботе, потому что у государства есть возможность изменить после того, как был вызван вызов 'setjmp', но перед вызовами' longjmp'. Это похоже на запись 'int x = 5, y = 6; while (y--) {printf ("x ==% u \ n", x); х = 0; } 'и ожидая, что он всегда будет говорить, что x равен 5, потому что это то, что ему было присвоено последнему номеру строки, но вы игнорируете будущие значения (за исключением циклов w/setjmp/longjmp, проблема может быть усилена). – nategoose

+0

В спецификации фактически указывается любая энергонезависимая переменная, назначенная после вызова setjmp(), не определена после вызова longjmp(). – Joshua

0

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

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

+0

Я не беспокоюсь о других компиляторах. Предоставляет ли GCC гарантию того, что '__builtin_expect' работает в этой ситуации, или это просто то, на что я надеюсь? –

+0

__builtin_expect - такая же вещь, как #pragma. Прочтите документы. – Joshua

+0

Лично у меня есть все основания думать, что gcc пойдет правильно. – Joshua