4

我想使用 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;
  }
}

多了一个变数,好像不太好看……

4

2 回答 2

3

来自C99 的基本原理

对 setjmp 提出的一个要求是它可以像任何其他函数一样使用,也就是说,它可以在任何表达式上下文中调用,并且无论从 setjmp 的返回是直接返回还是通过调用 longjmp,表达式都能正确评估。不幸的是,任何作为常规被调用函数的 setjmp 实现都无法对调用环境有足够的了解,无法保存在表达式求值过程中使用的任何临时寄存器或动态堆栈位置。(setjmp 宏似乎只有在它扩展为内联汇编代码或调用特殊的内置函数时才有帮助。)临时对象在对 setjmp 的初始调用时可能是正确的,但不太可能在由对 longjmp 的相应调用。

C89 委员会考虑的一个替代提案是要求实现认识到调用 setjmp 是一种特殊情况,因此他们采取任何必要的预防措施来在 longjmp 调用时正确恢复 setjmp 环境。这个提议被拒绝了,理由是一致性:目前允许实现专门实现库函数,但没有其他情况需要特殊处理。

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

于 2014-04-06T11:32:38.503 回答
0

POSIX.1确实指定了这些限制。但是,在 Linux 上,setjmp(3)并没有提到它们,所以在那个平台上你可以简单地做:

int retval = setjmp(jb);

当然,这是以牺牲一些便携性为代价的,但我不知道它有多糟糕。

于 2014-04-06T11:15:16.453 回答