c-为什么GCC优化了重要的分配,使其成为不同的程序行为



因此,我正在为控制台解释器制作一个C程序,以检测它是哪种类型,然后将它返回到typeret,并将指针存储到空指针retpoint中。现在,我要问的不是代码中有什么,而是为什么GCC在我的函数eval中优化这个赋值。我想知道GCC为什么优化一些实际上很重要的东西。

int eval(wchar_t *expr) {
// ....

if (expr[0] == L''' && expr[csize - 1] == L''') { // <-- Ignore this.
expr[csize - 1] = 0;
typeret         = 0;

retpoint    = (expr + 1);
} else if (strin(L".", expr)) { // <-- Ignore this.
typeret     = 2;
} else {
typeret     = 1;
tvar        = _wtoi(expr); // <-- Here is the problem.
retpoint    = &tvar;
}

return 0;
}

当我使用GCC命令gcc -Wsomewarning -o cim.exe cim.c -Os -s -ffunction-sections -fdata-sections -O3编译代码时,不会检测到赋值(即使没有-ffunction-sections-fdata-sections,也不会检测到分配(。

但是,当我更改涉及tvar周围或_wtoi周围的代码时,赋值不会被忽略。这是一个示例代码,其中赋值不会被忽略。

int eval(wchar_t *expr) {
int
tvar; // If I set tvar to N, then the assignment is still ignored (making tvar = N).
// ....
if (expr[0] == L''' && expr[csize - 1] == L''') { // <-- Ignore this.
expr[csize - 1] = 0;
typeret         = 0;
retpoint    = (expr + 1);
} else if (strin(L".", expr)) { // <-- Ignore this.
typeret     = 2;
} else {
typeret     = 1;
tvar        = _wtoi(expr); // <-- Here is the problem.
wprintf(L"%d", tvar); // or wprintf(L"%d", _wtoi(expr);
retpoint    = &tvar;
}
return 0;
}

现在,当然,如果我使用gcc -o cim.exe cim.c(没有优化(,第一个代码工作得很好;然而,该尺寸是优化后的尺寸的四倍。

注意

我确信这个程序中没有未定义的行为,我确信我已经正确地给出了数据。

typeretretpoint是全局数据,而tvar是局部变量。

编辑

我忘了提到我在Windows10中使用了GCC版本(tdm64-1(4.9.2。

提前谢谢。

在第一个示例中,在赋值tvar = _wtoi(expr);和函数eval返回之间,变量tvar不会被直接访问,也不会通过指针retpoint访问,之后tvar的生存期结束,因为它是本地的。并且您只能在tvar的使用寿命内访问它。因此编译器完全有权优化赋值,因为它不会对正确的程序产生任何影响。

如果它确实改变了程序的行为,那么您可能在某个地方有未定义的行为。在eval返回之后,您可能正在取消引用指针retpoint。那绝对是UB。通常,将全局指针设置为指向局部变量,并在函数返回后将其留在那里是非常可疑的。

最新更新