Безопасное использование longjmp/setjmp с volatile
Я рассматриваю использовать макрос TRY/CATCH на основе setjmp/longjmp для обработки ошибок. В противном случае некоторые из моих довольно структурированных функций будут взорваны уродливыми операторами if и флагами цикла.
Код похож на этот пример:
int trycatchtest(int i)
{
int result = 0;
volatile int error = 100;
volatile uint32_t *var = NULL;
TRY
{
error = 0;
var = os_malloc(4);
*var = 11;
if (i) THROW( i );
}
FINALLY
{
result = *var;
}
END;
return result;
}
THROW на самом деле макрос
#define TRY do { jmp_buf buf; switch( setjmp(buf) ) { case 0: while(1) {
#define FINALLY break; } default: {
#define END break; } } } while(0)
#define THROW(x) longjmp(buf, x)
Эта проблема:
Когда генерируется исключение (например, i=1), указатель var сбрасывается в NULL, хотя я использовал ключевое слово volatile, которое должно избегать использования регистра для него. Из отладчика я вижу, что он все еще находится в регистре, а не в памяти.
Я сделал ошибку?
РЕДАКТИРОВАТЬ:
Я изменил объявление var в
uint32_t * volatile var = NULL;
Это работает;-)
Я не очень понимаю, в чем разница
volatile uint32_t * var = NULL;
означает, что VALUE является изменчивым, тогда как прежняя декларация делает указатель изменчивым?
1 ответ
u32 *volatile var
делает указатель изменчивым, в то время как volatile u32 *var
сообщает компилятору, что данные по этому адресу нестабильны. Так как в последнем примере указатель не является изменчивым, я не удивлюсь, если ваш компилятор оптимизирует default
дело полностью к чему-то вроде result = NULL;
,
Это, вероятно, не ожидает setjmp
волшебство, и они печально известны тем, что даже "более спагетти, чем goto
".