这个setjmp / longjmp上下文中的自动变量是什么?

时间:2011-09-01 13:51:01

标签: c unix

UNIX环境中的高级编程由W. Richard Stevens声明:

  

“自动变量和寄存器的状态是什么   主函数中的变量?“

关于当你longjmp从堆栈下方某处回到main(或其他函数)时会发生什么。

接着说:

  

“这取决于。大多数实现都不会尝试回滚这些   自动变量和寄存器变量,但所有标准   说是他们的价值观是不确定的。如果你有自动   你不想回滚的变量,用它来定义它   volatile属性。声明为全局或静态的变量   执行longjmp时保持不变。

似乎他说正常的堆栈变量不会将它们的值设置回setjmp时的值 - 但是在longjmp返回之后,函数的其余部分不能依赖于它的堆栈变量对它来说似乎很疯狂,所以我猜我错了。

有人可以为我定义“自动变量”并解释具体没有恢复到原始值的原因以及为什么会这样?

5 个答案:

答案 0 :(得分:6)

所有它的说法是,如果

  1. 你有一个未声明为volatile的自动(函数本地非静态)变量;和
  2. 您在setjmplongjmp
  3. 之间更改变量的值

    然后在longjmp之后该变量的值变得不确定。

    我认为这与这些变量驻留在CPU寄存器而不是RAM中的可能性有关,以及在longjmp中保留此类变量值的相关难度。

    以下是gcc manual

    的引用
      

    如果您使用longjmp,请注意自动变量。 ISO C说   未声明为volatile的自动变量未定义   longjmp之后的值。这是海湾合作委员会所做的所有承诺,因为   正确恢复寄存器变量非常困难,其中之一   GCC的特点是它可以将变量放在寄存器中   你问它。

    如果变量值的潜在丢失在您的用例中存在问题,请将相关变量声明为volatile

答案 1 :(得分:6)

“自动变量”是普通(未使用寄存器或静态声明)局部变量的旧术语,它可以追溯到C标准中使用的术语以及auto关键字的原始含义。参见the standard

的6.2.4和6.7.1节

至于此:

  

然后其余的函数在longjmp回到它之后无法依赖它的堆栈变量这看起来很疯狂

这个想法是,如果你要去longjmp,你不应该首先修改它们,因为那样你就不知道会发生什么。

原因是longjmp可以恢复状态,例如处理器寄存器,自动变量可能已被映射到(不能保证它们将位于“堆栈”或内存中) 。即使它们确实存在于内存中,某些操作也可能[除非它被声明为volatile]直接访问内存但可能访问已经加载了值的处理器寄存器。

你的问题有点奇怪,因为它意味着你希望它们被恢复[即你想要删除的干预功能的修改] - 一般来说,这个警告警告说,当它没有被预期时,它们可能会被意外恢复。 “未恢复”并不意味着“无法使用”[虽然标准DOES声明它们不可用,因为它可能会恢复缓存的寄存器而不是内存,因此您将得到不一致的结果],这意味着“具有后来函数写入的值它(因为你传递了打算写入的地址)“。

答案 2 :(得分:0)

自动变量是常规的函数局部变量 - 因为它们是在堆栈上分配的,您不必关心它们的内存,它们被称为自动

有关更深入的说明,请参阅http://en.wikipedia.org/wiki/Automatic_variable

答案 3 :(得分:0)

auto表示函数本地的任何内容,并未明确定义为static。值得注意的是,该标准几乎规定了他所陈述的行为(§7.13.2/ 3):

  

所有可访问的对象都具有值以及抽象机器的所有其他组件   有状态,截至调用longjmp函数时,除了值的   自动存储持续时间的对象是包含该函数的函数的本地对象   调用没有volatile限定类型的相应setjmp宏   并且在setjmp调用和longjmp调用之间进行了更改   不确定的。

答案 4 :(得分:0)

我无法定义“自动变量”,但也许可以帮助您了解setjump期间发生的情况:

  

(部分)CPU注册并保存到文件中。

longjump期间:

  

CPU寄存器的值被重置为保存的值。

别无其他! (here就是一个例子)

所以在longjump期间,你只需要回到堆栈中更高的位置,将所有变量保存在内存中未触及,以及一些(不是全部)寄存器,特别是stack pointerinstruction pointer重置为setjmp期间的值。