请参阅以下在C和C ++中有效的代码:
extern int output;
extern int input;
extern int error_flag;
void func(void)
{
if (0 != error_flag)
{
output = -1;
}
else
{
output = input;
}
}
是否允许编译器以与下面类似的方式编译上述代码?
extern int output;
extern int input;
extern int error_flag;
void func(void)
{
output = -1;
if (0 == error_flag)
{
output = input;
}
}
换句话说,是否允许编译器生成(从第一个代码段)代码,该代码始终将-1临时赋值为output
,然后将input
值分配给output
取决于error_flag
状态?
如果将output
声明为volatile,编译器是否可以这样做?
如果将output
声明为atomic_int
(stdatomic.h),是否允许编译器执行此操作?
David Schwartz发表评论后的更新:
如果编译器可以自由地向变量添加额外的写入,则似乎无法从C代码中判断是否存在数据争用。如何确定?
答案 0 :(得分:2)
是的,允许编译器进行这种优化。通常,您可以假设编译器(以及CPU也可以)重新排序代码,假设它在单个线程中运行。如果您有多个线程,则需要进行同步。如果您没有同步并且您的代码写入写入或读取另一个线程的内存位置,则您的代码包含数据争用,在C ++中这是未定义的行为。
volatile
不会改变数据竞争问题。但是,如果是IIRC,则不允许编译器对读取和写入volatile
变量进行重新排序。
使用atomic_int
时,编译器仍然可以执行某些优化。我不认为编译器可以发明写入(这可能打破多线程程序)。但是,它仍然可以重新排序操作,所以要小心。