在摆弄一些测试代码时,我在以下代码中观察到:
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*
一样 - 或者是否实际上不允许对其进行优化。
答案 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
标志会导致任何指针类型在原始代码中不优化。因此,我猜想编译器在他们对别名的警惕时不进行优化的原因。要么是因为:
volatile
内存(?)