使用volatile限定词可以抑制编译器警告

时间:2018-11-16 18:59:58

标签: c volatile

今天,我正在查看一个家伙的代码,在那里他声明了一个变量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;   
}

现在,我无法弄清两件事:

  1. 我应该启用哪个确切的gcc标志以获取此警告?
  2. 为什么将i声明为volatile可以抑制该警告?

3 个答案:

答案 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)

  1. 该警告告诉您启用了哪个标志:-Waggressive-loop-optimizations
  2. 声明变量volatile意味着编译器必须假定编译器控制范围之外的内容可能会检查和修改该变量。因此,不能假设i会使用值4(或者i += 2总是将i的值加2,等等)。