c++编译器能否消除未读的易失性局部变量?

visual Can a C++ Compiler Eliminate a Volatile Local Var that is not Read

本文关键字:易失性 局部变量 编译器 c++      更新时间:2023-10-16

比如说,我有这样的代码:

int f() {
  volatile int c;
  c=34;
  return abc();
}

不读取volatile int c。但是它被标记为volatile,编译器可以完全消除它吗?我在Visual c++ 2010中进行的测试显示出相互矛盾的结果。在vc++中,如果我启用优化(最大化速度),上面的函数包含一个名为c的局部变量(通过查看生成的程序集清单)。但是,我没有使用赋值操作符,而是尝试使用memset()等编译器内部函数初始化变量(并启用编译器内部函数),结果该变量被消除了。

int f() {
  volatile int c;
  memset((void*)&c,34, 1); 
  return abc();
}

那么根据c++标准,编译器能否消除volatile int ?我认为可能有一些不一致的行为在vc++有关如何内在函数优化易失性变量。

memset((void*)&c,34, 1);具有未定义的行为(§7.1.6.1/6)。因此,编译器可以产生任何结果。

如果试图通过使用具有非易失性限定类型的glvalue来引用用易失性限定类型定义的对象,则程序的行为是未定义的。

请不要使用这样的强制转换,更不用说c风格的强制转换了。当不知道特定情况下正确的c++强制类型转换是什么时,很可能是不应该强制类型转换的情况。

那么根据c++标准,编译器能否消除volatile int ?

没有

volatile限定对象用于对硬件进行读写,分配volatile对象的副作用是可以观察到的。

因此,根据所谓的"as-if"规则对优化的约束,不允许符合的实现优化掉c。"as-if"规则在c++ 11标准的第1.9/1段中正式引入:

本国际标准中的语义描述定义了一个参数化的不确定性抽象机器。本国际标准对一致性实现的结构没有要求。特别是,它们不需要复制或模拟抽象机器的结构。相反,符合如前所述,实现需要模拟(仅)抽象机器的可观察行为

"可观察行为"的概念在第1.9/8段中定义:

一致性实现的最低要求是:

- 对易失性对象的访问严格按照抽象机的规则求值。

-在程序结束时,写入文件的所有数据应与程序执行时可能得到的结果之一相同根据抽象语义执行程序将产生。

—交互设备的输入和输出动态应以这样一种方式发生:提示输出实际上是在程序等待输入之前交付的。什么是互动设备是由实现定义的。

这些统称为程序可观察行为。[…]

由于对volatile对象的访问必须严格按照抽象机的规则求值,编译器不允许优化去掉c和相应的赋值操作。