char *与之前指令中设置的值的比较没有被优化掉?

时间:2017-01-12 20:30:42

标签: c++ optimization language-lawyer strict-aliasing

在摆弄一些测试代码时,我在以下代码中观察到:

extern char* pc;
int muysimple() {
  *pc = 0;
  if (*pc != 0) { return 1111; }

  return 4444;
}

我可以在godbolt上选择的任何编译器 进行比较。

如果我将extern char*更改为extern int*,则会优化比较

为什么gcc和clang都会保留char的比较,即使此代码中似乎没有任何内容可以合法地更改值,以便比较评估为真?

语言规范中是否有任何内容禁止通过char* 进行写/读的优化(但允许优化int* !)或优化者是否更加保守?#/ p>

正如已经提到的那样:我不明白 - 明智的 - 如何在这里发挥别名规则。这个代码只有一个变量可见,没有多线程或任何地方的调用。

当然,char别名规则很可能是编译器没有对此进行优化的实际原因,但问题是编译器是否可以优化char*的内容与int*一样 - 或者是否实际上不允许对其进行优化。

2 个答案:

答案 0 :(得分:6)

  

即使此代码中似乎没有任何内容可以合法地更改值,以便比较评估为true?

pc = (char *) &pc;是有效的分配,由于char左值可用于访问任何POD类型,因此*pc的分配可能会更改pc

答案 1 :(得分:1)

允许char*允许别名任何包含volatile内存。

使用-fpermissive标记,gcc只会发出关于指向易失性内存的char*的警告,但compiles

由于在您的示例中指针是extern,因此可能使用此标志编译另一个转换,因此指针指向volatile内存。因此,无法进行优化。

我没有找到关于非易失性char*别名volatile内存是否合法或UB的官方参考。

编辑: 看起来为int*volatile int*的分配给出了相同的警告,在这种情况下编译器会进行优化。所以我猜警告/许可标志并不相关。问题在于,char*一般是否允许对volatile内存进行别名。

这里有一个example"聪明地"使用C ++强制转换对volatile struct进行别名而不显示任何警告。

EDIT2:看起来添加-fno-strict-aliasing标志会导致任何指针类型在原始代码中不优化。因此,我猜想编译器在他们对别名的警惕时不进行优化的原因。要么是因为:

  1. 允许别名volatile内存(?)
  2. 害怕数据与其他指针指向同一个非易失性内存。 @alain在他的回答中提到数据竞争是UB,但即使这是真的,我想编译器制造商决定在这里小心,而不是优化。
相关问题