今天,我正在查看一个家伙的代码,在那里他声明了一个变量volatile
。在询问时,他告诉它在某些系统上会产生奇怪的行为。
在删除volatile并进行编译时,它会产生此编译器警告
iteration 2 invokes undefined behavior [-Waggressive-loop-optimizations]
代码与下面的代码非常相似,数组不受限制地被访问。 由于他使用了与Makefile不同的其他代码库,因此该警告未在他的系统上产生。
int a[4]={1,2,3,4};
int i; //when declared volatile int i, doesn't produce warning
i=0;
while(i<5) {
printf("%d\t", a[i]); //a[4] will invoke undefined behavior
i+=2;
}
现在,我无法弄清两件事:
i
声明为volatile可以抑制该警告?答案 0 :(得分:3)
积极的循环优化看到以下代码时...
int i;
i=0;
while(i<5) {
printf("%d\t", a[i]);
i+=2;
}
...它将使用一种称为“循环展开”的技术来重写它,就像这样...
printf("%d\t", a[0]);
printf("%d\t", a[2]);
printf("%d\t", a[4]);
问题!迭代0和1很好,但是迭代2将执行越界数组访问,并调用未定义的行为。这就是为什么您收到警告的原因。
将i
声明为volatile
会阻止编译器执行此优化操作(因为不能确定在循环执行期间其他进程是否没有修改i
的值) ,因此它必须保留原样的代码。您仍然有未定义的行为,只是编译器没有警告您。总而言之,这是您同事的糟糕“解决方案”。
答案 1 :(得分:2)
您未定义的行为是循环允许i = 4,该值将读取数组的末尾。循环优化器注意到了这一点,但是无论优化如何,这都是一个问题。
volatile
告诉编译器可以在此代码外部更改i
的值。这样做的实际效果是,编译器无法执行依赖于假设i
的值的优化。这会关闭注意到您的问题的优化。
仅使用volatile
绕过警告是很糟糕的做法。而是将while
条件更改为while (i < 4)
。
答案 2 :(得分:1)
-Waggressive-loop-optimizations
volatile
意味着编译器必须假定编译器控制范围之外的内容可能会检查和修改该变量。因此,不能假设i
会使用值4
(或者i += 2
总是将i
的值加2,等等)。