我怎么知道gcc是否同意某些东西是不稳定的?

考虑以下:

volatile uint32_t i; 

我如何知道gcc是否确实将我视为易变? 它将被声明为是因为没有附近的代码将修改它,并且它的修改可能是由于某些中断。

我不是世界上最差的汇编程序员,但我在电视上播放一个。 有人可以帮我理解它会有什么不同吗?

如果你采取以下愚蠢的代码:

 #include  #include  volatile uint32_t i; int main(void) { if (i == 64738) return 0; else return 1; } 

将其编译为对象格式并通过objdump反汇编,然后在删除’volatile’后执行相同操作,没有区别(根据diff)。 volatile声明是否太接近于其检查或修改的位置,或者我在声明易失性时应该总是使用某种primefaces类型? 一些优化标志会影响这个吗?

请注意,我的愚蠢样本并不完全符合我的问题,我意识到这一点。 我只是试图找出gcc是否确实将变量视为易失性,所以我正在研究小型转储以试图找到差异。

在某些情况下,许多编译器不会按照应有的方式处理volatile。 如果您处理挥发物以避免令人讨厌的意外,请参阅本文: 挥发物被错误编译,以及如何处理它 。 它还包含对标准引用支持的volatile的非常好的描述。

要100%确定,并且对于这样一个简单的示例,请检查assembly输出。

尝试在循环外设置变量并在循环内读取它。 在非易失性情况下,编译器可能(或可能不)将其推入寄存器或使其成为编译时常量或循环之前的某些东西,因为它“知道”它不会改变,而如果它是不稳定的,它将会每次通过循环从变量空间读取它。

基本上,当您将某些内容声明为volatile时,您告诉编译器不要进行某些优化。 如果它决定不进行那些优化,你不知道它没有做它们因为它被声明为volatile,或者只是它决定它需要那些寄存器用于别的东西,或者它没有注意到它可以转向它进入编译时常量。

据我所知,volatile有助于优化器。 例如,如果您的代码如下所示:

 int foo() { int x = 0; while (x); return 42; } 

“while”循环将在二进制文件中进行优化。

但是如果将’x’定义为volatile(即volatile int x; ),那么编译器将单独保留循环。

你的小样本不足以显示任何东西。 volatile变量与不变量之间的区别在于代码中的每个加载或存储都必须在可执行文件中为volatile变量生成一个加载或存储,而编译器可以自由地优化非加载或存储的非变量 – 易变量。 如果你的样品中有一个i加载,那就是我对挥发性和非挥发性的预期。

为了显示差异,您将不得不拥有冗余负载和/或存储。 尝试类似的东西

 int i = 5; int j = i + 2; i = 5; i = 5; printf("%d %d\n", i, j); 

在非易失性和易变性之间改变我。 您可能必须启用某种级别的优化才能看到差异。

那里的代码有三个存储和两个i的加载,可以优化到一个存储,如果我不是易失性,可能是一个加载。 如果i被声明为volatile,则无论优化是什么,所有存储和加载都应按顺序显示在目标代码中。 如果他们不这样做,你就会遇到编译错误。

它应该始终将其视为易变的。

代码相同的原因是volatile只是指示编译器每次访问它时从内存加载变量。 即使进行了优化,编译器仍然需要在您编写的代码中从内存中加载i一次,因为它无法在编译时推断出i的值。 如果您反复访问它,您会看到不同之处。

任何现代编译器都有多个阶段。 一个相当容易但有趣的问题是变量本身的声明是否被正确解析。 这很容易,因为C ++名称修改应该根据volatile的不同而不同。 因此,如果您编译两次,一次使用volatile定义,则符号表应略有不同。

在错误引用或downvote之前阅读标准。 这是n2798的引用:

7.1.6.1 cv限定符

7注意:volatile是对实现的暗示,以避免涉及对象的积极优化,因为对象的值可能会被实现无法检测的方式更改。 有关详细语义,请参见1.9。 通常,volatile的语义在C ++中与在C中的相同。

关键字volatile作为提示。 很像register关键字。 但是, volatile要求编译器保留所有优化function。 这样,它不会在变量寄存器或缓存中保留变量的副本(以优化访问速度),而是每次请求时从内存中获取变量。

由于存在很多混乱:还有一些。 事实上,C99标准确实说每次读取时都必须查找一个易变的合格对象,等等其他人已经注意到了。 但是,还有另一部分说明构成易失性访问的是实现定义。 因此,一个知道内部硬件的编译器会知道,例如,当你有一个自动的volatile限定变量并且它的地址永远不会被占用时,它将不会被放入敏感的内存区域并且几乎肯定会被忽略提示并优化它。

此关键字在setjmplongjmp类型的error handling中查找用法。 您唯一需要记住的是:当您认为变量可能发生变化时,您会提供volatile关键字。 也就是说,您可以使用普通对象并使用一些演员来管理。

需要记住的另一件事是,对于实现,标准保留了构成易失性访问的定义。

如果你真的想要不同的汇编编译与优化