c - 如何安全的获取setjmp的返回值

标签 c setjmp

我想使用 longjmp 返回一个错误代码,并从调用 setjmp 的函数传递它。简化代码:

int do_things(stuff ........)
{
 int error_code;
 jmp_buf jb;

 if ((error_code = setjmp(jb)) == 0) {
    /* do stuff */
    return 0;
 }
 else {
    return error_code;
 }
}

但我读过:
“对 setjmp 宏的调用应仅出现在以下上下文之一中:”
 the entire controlling expression of a selection or iteration statement

if (setjmp(jb)) {
switch (setjmp(jb)) {
while (setjmp(jb)) {

或者
 one operand of a relational or equality operator with the other operand
 an integer constant expression, with the resulting expression being
 the entire controlling expression of a selection or iteration statement

if (setjmp(jb) < 3) {

或者
 the operand of a unary ! operator with the resulting
 expression being the entire controlling expression of a
 selection or iteration statement

if (!setjmp(jb)) {

或者
 the entire expression of an expression statement (possibly cast to void).

setjmp(bf); 

有没有一个很好的方法来获取返回值?
(不使用 switch ,并为所有可能的值写一个 case )

编辑

感谢 Matt 在 c99 原理中找到它。
我现在想到的是:
int do_things(stuff ........)
{
  volatile error_code;
  jmp_buf jb;

  if (setjmp(jb) == 0) {
     working_some(&error_code, ....);
     working_again(&error_code, ....);
     working_more(&error_code, ....);
     working_for_fun(&error_code, ....);
     return 0;
  }
  else {
     general_cleanup();
     return error_code;
  }
}

还有一个变量,看起来不太好......

最佳答案

来自 C99 rationale :

One proposed requirement on setjmp is that it be usable like any other function, that is, that it be callable in any expression context, and that the expression evaluate correctly whether the return from setjmp is direct or via a call to longjmp. Unfortunately, any implementation of setjmp as a conventional called function cannot know enough about the calling environment to save any temporary registers or dynamic stack locations used part way through an expression evaluation. (A setjmp macro seems to help only if it expands to inline assembly code or a call to a special built-in function.) The temporaries may be correct on the initial call to setjmp, but are not likely to be on any return initiated by a corresponding call to longjmp. These considerations dictated the constraint that setjmp be called only from within fairly simple expressions, ones not likely to need temporary storage.

An alternative proposal considered by the C89 Committee was to require that implementations recognize that calling setjmp is a special case, and hence that they take whatever precautions are necessary to restore the setjmp environment properly upon a longjmp call. This proposal was rejected on grounds of consistency: implementations are currently allowed to implement library functions specially, but no other situations require special treatment.



我对此的解释是,指定 a = setjmp(jb); 被认为过于严格。必须工作。所以标准没有定义它。但是特定的编译器可能会选择支持这一点(并且希望能够记录下来)。为了便于移植,我想您应该使用一些预处理器检查来验证代码是否正在使用已知支持此功能的编译器进行编译。

关于c - 如何安全的获取setjmp的返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22893178/

相关文章:

c - 栈是如何展开的,栈帧是如何识别的

c++ - 此代码是否包含隐藏的错误?

linux - setjmp 和 longjmp - 通过示例理解

c - longjmp(buffer, 0) 不返回 0

c - VS2010 多项目解决方案 - 控制台和表单应用程序

C、这条线是做什么的?

c - Win32 (GDI) - 设置 STATIC 控件的不透明度

c - 使用 C 返回数组

c - linux C语言。 setjmp longjmp 报警

c - 为什么调用 setjmp() 中的函数会发生段错误?