Безопасное использование 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".

Другие вопросы по тегам