考虑以下:
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声明是否太接近于其检查或修改的位置,或者我在声明易失性时应该总是使用某种原子类型?一些优化标志会影响这个吗?
请注意,我的愚蠢样本并不完全符合我的问题,我意识到这一点.我只是试图找出gcc是否确实将变量视为易失性,所以我正在研究小型转储以试图找到差异.
在某些情况下,许多编译器不会按照应有的方式处理volatile.如果您处理挥发物以避免令人讨厌的意外,请参阅本文:挥发物被错误编译,以及如何处理它.它还包含对标准引用支持的volatile的非常好的描述.
要100%确定,并且对于这样一个简单的示例,请检查装配输出.
尝试在循环外设置变量并在循环内读取它.在非易失性情况下,编译器可能(或可能不)将其推入寄存器或使其成为编译时常量或循环之前的某些东西,因为它"知道"它不会改变,而如果它是不稳定的,它将会每次通过循环从变量空间中读取它.
基本上,当您将某些内容声明为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,则无论优化是什么,所有存储和加载都应按顺序显示在目标代码中.如果他们不这样做,你就会遇到编译错误.