【问题标题】:What is an automatic variable in this setjmp/longjmp context?这个 setjmp/longjmp 上下文中的自动变量是什么?
【发布时间】:2011-09-01 13:51:00
【问题描述】:

W. Richard Stevens 的《UNIX 环境中的高级编程》指出:

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

关于当你 longjmp 从堆栈下方的某个位置返回主函数(或其他函数)时会发生什么。

接着说:

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

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

有人可以为我定义“自动变量”并解释具体是什么没有设置回其原始值以及为什么会这样吗?

【问题讨论】:

  • 自动变量只是一个具有auto 存储类的变量,这是没有其他存储类声明的函数变量的默认值。这是一个关键字,你知道的。

标签: c unix


【解决方案1】:

它只是说如果

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

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

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

这是gcc manual的引述:

如果您使用longjmp,请注意自动变量。 ISO C 说 未声明 volatile 的自动变量未定义 longjmp 之后的值。这就是 GCC 承诺要做的所有事情,因为 正确恢复寄存器变量是非常困难的,而且一个 GCC 的特点是它可以将变量放入寄存器中,而无需 你的要求。

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

【讨论】:

  • 当然,那个 gcc 手动引用是一个糟糕的解释:这实际上不是 ISO C 所说的。 如果它们被修改,它只会使其未定义,而困难的是不恢复它们(毕竟,您可以保存和恢复所有寄存器)而是避免不必要的恢复。
  • 确实,这个 UB 的 原因 是很容易保存所有寄存器值并恢复它们,但实现跟踪 哪个是不切实际的值的副本(内存中的一个或缓存在寄存器中的那个)在longjmp 发生时是最新的。
  • @Random832:谢谢 - 我已经编辑了答案,试图进一步澄清事情。
  • @R:问题不仅仅是知道某些变量不应该回滚。如果例程调用 setjmp(),并对局部变量进行一些更改,然后调用例程 foo(),最终调用 longjmp(),编译器可以判断在 foo() 之后不需要变量的值) 返回,编译器可以将变量分配到临时寄存器,这样通过执行 longjmp(),这些变量可能在 setjmp() 之后存储在其中的任何信息都将消失。
【解决方案2】:

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

至于这个:

但是在 longjmp 回到它之后,函数的其余部分不能依赖它的堆栈变量,这似乎很疯狂

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

原因是 longjmp 可能会恢复处理器寄存器等状态,自动变量可能已映射到这些状态(无法保证它们会在“堆栈”上或内存中) . 并且即使它们确实存在于内存中,某些操作可能不会[除非它被声明为 volatile] 直接访问内存,而是可以访问值已经加载到的处理器寄存器)

您的问题有点奇怪,因为它暗示您会希望恢复它们[即您对要删除的干预函数的修改] - 一般来说,这个警告是警告它们可能会在不期望的情况下被意外恢复。 “未恢复”并不意味着“不可用”[尽管标准确实声明它们不可用,因为它可能会恢复缓存的寄存器而不是内存,因此您会得到不一致的结果],它的意思是“具有稍后函数写入的值它(因为您传递了打算将其写入的地址)”。

【讨论】:

  • 奇怪的是,今天有这么多人似乎已经忘记了 C 的四个基本 storage class keywords 变量:autostaticregisterextern — 尽管 @987654329 @ 变量是 something different,充其量是可疑的。
【解决方案3】:

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

请参阅http://en.wikipedia.org/wiki/Automatic_variable 以获得更深入的描述。

【讨论】:

    【解决方案4】:

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

    (部分)CPU 寄存器并保存到文件中。

    longjump期间:

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

    没有别的了! (here 就是一个例子)

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

    【讨论】:

      【解决方案5】:

      auto 表示函数本地的任何内容,并且没有专门定义为static。可能值得注意的是,该标准几乎指定了他所说的行为(第 7.13.2/3 节):

      所有可访问对象都有值,抽象机器的所有其他组件 有状态,截至调用 longjmp 函数时,除了 自动存储持续时间的对象,它们是包含 调用不具有 volatile 限定类型的相应 setjmp 宏 并且在 setjmp 调用和 longjmp 调用之间发生了变化 不确定。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-10-30
        • 1970-01-01
        • 2011-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多