UNIX环境中的高级编程由W. Richard Stevens声明:
“自动变量和寄存器的状态是什么 主函数中的变量?“
关于当你longjmp
从堆栈下方某处回到main(或其他函数)时会发生什么。
接着说:
“这取决于。大多数实现都不会尝试回滚这些 自动变量和寄存器变量,但所有标准 说是他们的价值观是不确定的。如果你有自动 你不想回滚的变量,用它来定义它
volatile
属性。声明为全局或静态的变量 执行longjmp
时保持不变。
似乎他说正常的堆栈变量不会将它们的值设置回setjmp时的值 - 但是在longjmp返回之后,函数的其余部分不能依赖于它的堆栈变量对它来说似乎很疯狂,所以我猜我错了。
有人可以为我定义“自动变量”并解释具体没有恢复到原始值的原因以及为什么会这样?
答案 0 :(得分:6)
所有它的说法是,如果
volatile
的自动(函数本地非静态)变量;和setjmp
和longjmp
然后在longjmp
之后该变量的值变得不确定。
我认为这与这些变量驻留在CPU寄存器而不是RAM中的可能性有关,以及在longjmp
中保留此类变量值的相关难度。
以下是gcc
manual:
如果您使用
longjmp
,请注意自动变量。 ISO C说 未声明为volatile
的自动变量未定义longjmp
之后的值。这是海湾合作委员会所做的所有承诺,因为 正确恢复寄存器变量非常困难,其中之一 GCC的特点是它可以将变量放在寄存器中 你问它。
如果变量值的潜在丢失在您的用例中存在问题,请将相关变量声明为volatile
。
答案 1 :(得分:6)
“自动变量”是普通(未使用寄存器或静态声明)局部变量的旧术语,它可以追溯到C标准中使用的术语以及auto
关键字的原始含义。参见the standard
至于此:
然后其余的函数在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
期间:
别无其他! (here就是一个例子)CPU寄存器的值被重置为保存的值。
所以在longjump
期间,你只需要回到堆栈中更高的位置,将所有变量保存在内存中未触及,以及一些(不是全部)寄存器,特别是stack pointer
和instruction pointer
重置为setjmp
期间的值。