【问题标题】:Can an uninitialized automatic volatile variable in C be safely read?可以安全读取 C 中未初始化的自动 volatile 变量吗?
【发布时间】:2015-02-27 12:14:28
【问题描述】:

在 C 中,我可以访问自动 volatile 变量而无需先对其进行初始化,还是它总是导致未定义的行为?

例如,在某些映射到 volatile 变量的硬件设备中,初始化变量无论如何都没有意义,甚至可能被禁止。

【问题讨论】:

  • 如何声明变量?它是否使用一些编译器扩展进行映射?还是你在使用指针?
  • 如果硬件寄存器映射到变量,那么我非常怀疑这些变量是否具有自动存储持续时间。因此,这个问题没有意义。请给出您的意思的示例代码。
  • 映射到硬件设备的 volatile 变量不会是 automatic
  • 为什么看不懂?它不一定是 UB。
  • @MartinJames 因为它是一个未初始化的变量,具有不确定的值。使用具有不确定值的变量会导致未定义的行为

标签: c volatile undefined-behavior


【解决方案1】:

自动变量通常位于call stack(但这是特定于实现的),因此它通常不会是某些特定于硬件的“设备”(除非您的堆栈指针是垃圾)。在这种情况下(在堆栈上),变量继承自该堆栈位置的先前内容。如果它是不稳定的,例如,像

void foo(void) {
  volatile int x;
  // here x contains garbage
}

访问 x 会给出一些“不确定的值”,并且该访问是未定义的行为。

C 标准不需要任何调用堆栈,但大多数 C 实现使用机器调用堆栈。

当然,如果你有一个自动变量,它是指向一些易失数据的指针,情况就不同了。

【讨论】:

  • 硬件寄存器通常表示为指向volatile的指针,而那些指针当然可以是自动的。也许这让 OP 感到困惑。
  • @unwind 声明像 volatile int* ptr; 这样的指针不会使 指针变量 易变。它仍然是一个普通的自动存储变量(假设它是在本地范围内声明的)。为了使实际的指针易失,你必须写一些晦涩的东西,比如int* volatile ptr;。为什么有人愿意这样做,我不知道。
  • @Lundin 嗯,是的,这正是我所说的……或者至少是我想说的。指针在指向 volatile 数据时可以是自动的,但这并不能使自动的东西也成为 volatile 的东西。
【解决方案2】:

访问未初始化的变量(或内存位置)的值将导致 C 标准的未定义行为。这意味着 C 标准并没有说明会发生什么。

还有其他来源可以定义在某些情况下会发生什么。在 volatile 变量的情况下,发生的事情的定义几乎总是依赖于平台。

因此您需要查阅相关变量的相关文档。

【讨论】:

    【解决方案3】:

    如果变量是硬件内存映射的 I/O 位置,请使用 volatile,而不是 atomic,显然它应该仅在硬件需要初始化时才进行初始化。

    C++ 11 标准规定 volatile 不应用于非硬件内存映射 I/O。根据需要使用原子或同步类型之一(事件、互斥体、信号量...)提供Memory Barrier

    Microsoft 和可能的其他一些编译器具有供应商特定的扩展,这些扩展为内存屏障提供易失性变量(作为 VS2012 和更高版本中的命令行选项,始终在旧版本上启用),但这是非标准用法。

    【讨论】:

      猜你喜欢
      • 2022-11-21
      • 1970-01-01
      • 1970-01-01
      • 2010-12-30
      • 2021-11-18
      • 2016-05-11
      • 1970-01-01
      • 2012-04-18
      • 2017-03-16
      相关资源
      最近更新 更多