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

Why did GCC optimizes important assignment, making it into a different program behavior?

所以,我正在为我的控制台解释器制作一个 C 程序来检测它是哪种类型,然后 return 它到 typeret 并将指针存储到 void 指针 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 访问returns,然后 tvar 的生命周期结束,因为它是本地的。并且您只能在其生命周期内访问 tvar。所以编译器完全有权优化分配,因为它不会对正确的程序产生任何影响。

如果它确实改变了你程序的行为,那么你可能在某处有未定义的行为。也许您在 eval returns 之后取消引用指针 retpoint。那绝对是UB。一般来说,将全局指针设置为指向局部变量,并在函数之后将其留在那里returns,是非常可疑的。