longjmp/setjmp 与 volatile 的安全使用
Safe usage of longjmp/setjmp with volatile
我考虑使用基于 setjmp/longjmp 的 TRY/CATCH 宏来处理错误。否则我的一些非常结构化的函数将被丑陋的 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 是可变的,而前面的声明使指针可变?
u32 *volatile var
使 指针 可变,而 volatile u32 *var
告诉编译器该地址的数据是可变的。因此,由于在后一个示例中指针不是可变的,如果您的编译器将 default
案例完全优化为 result = NULL;
.
之类的东西,我不会感到惊讶。
它可能不会期待 setjmp
魔法,而且这些甚至因 "more spaghetti than goto
" 而臭名昭著。
我考虑使用基于 setjmp/longjmp 的 TRY/CATCH 宏来处理错误。否则我的一些非常结构化的函数将被丑陋的 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 是可变的,而前面的声明使指针可变?
u32 *volatile var
使 指针 可变,而 volatile u32 *var
告诉编译器该地址的数据是可变的。因此,由于在后一个示例中指针不是可变的,如果您的编译器将 default
案例完全优化为 result = NULL;
.
它可能不会期待 setjmp
魔法,而且这些甚至因 "more spaghetti than goto
" 而臭名昭著。