Visual Studio 2013 中可能存在的 C/C++ 编译器错误

Posted

技术标签:

【中文标题】Visual Studio 2013 中可能存在的 C/C++ 编译器错误【英文标题】:Possible C/C++ compiler bug in Visual Studio 2013 【发布时间】:2017-03-01 17:55:08 【问题描述】:

以下 C 或 C++ 代码的输出应为“11,11,11” 但是使用 Visual Studio Professional 2013(版本 12.0.40629.00 更新 5)输出为“11,0,0”!这仅发生在发布版本中,并在关闭优化时消失。这是编译器错误吗?

#include <stdio.h>

int main(void)

    int A[100] =  0 ;
    int row = 0;   // BUG disappears if we make this const or short or char...
    int ncols = 3; // BUG disappears if we make this const or short or char...

    for (int y = row; y <= row; ++y)
    
        for (int x = 0; x < ncols; ++x)
        
            const int index = y * ncols + x;

            //A[index] = 11;           // (no bug !)
            *(A + index) = 11;       // BUG!!!
            //*(A + y*ncols+x) = 11;   // (no bug !)
            //*(A + (y*ncols+x)) = 11; // BUG!!!
        
    

    for (int x = 0; x < ncols; ++x)
    
        printf("%d,", A[x]);
    

    return 0;

【问题讨论】:

无法在 MSVC 2015 中重现。这是显示问题的 Minimal, Complete, and Verifiable example 吗? 我无法使用 Visual C++ 2015 更新 3 重现声称的行为。 @WeatherVane 检查 VS 2013。 只是想说,在 clang 3.9.1 上通过 -O2 运行它(我知道,与问题无关,但我很好奇)会产生 pretty funny asm result。无论团队是谁进行循环分析都应该感到自豪 =) 在 VS15 和 VS13 上进行了测试,包括 cpp 和 c。每次输出都是预期的。您能否向我们提供编译器的确切版本号。生成的程序集也很有趣。 【参考方案1】:

是的,它似乎是一个编译器错误。在 Win32 版本的代码中,编译器使用寄存器 esi 表示 y 并使用寄存器 edx 表示 x。正如@Ajay Brahmakshatriya 在 cmets 中正确指出的那样,编译器似乎尝试交换循环(将外部与内部交换),但最终得到的代码不正确。最后一条条件跳转指令,它应该代表 [exchanged] 内部循环,由于某种原因,它也将控制转移到检查esi 的位置。该检查会提前结束迭代。

0018206B  xor         esi,esi             ; This is `y`
0018206D  xor         edx,edx             ; This is `x`
...
00182070  test        esi,esi  
00182072  jg          main+5Ch (018209Ch) ; Exit from the outer cycle?

00182074  lea         eax,[edx+esi*2]     ; Recalculate the starting storage location
00182077  add         eax,esi             ; for the next cycle:
00182079  lea         ecx,[A]             ; eax = esi * 3 + edx
0018207F  lea         eax,[ecx+eax*4]     ; eax = &A[eax]
...
00182082  mov         ecx,1               ; It is not exactly clear to me what this is 
00182087  sub         ecx,esi             ; supposed to do, but when `esi` is `0`, it 
00182089  add         esi,ecx             ; leaves `ecx` as 1, which is correct 
                                          ; number of iterations for outer cycle
...
00182090  mov         dword ptr [eax],0Bh ; Storing the value
00182096  lea         eax,[eax+0Ch]       ; Updating the pointer for the next storage location 
00182099  dec         ecx  
0018209A  jne         main+50h (0182090h) ; Outer cycle [exchanged]

0018209C  inc         edx  
0018209D  cmp         edx,3  
001820A0  jl          main+30h (0182070h) ; Inner cycle [exchanged]: for some reason it
                                          ; jumps to `test esi,esi`, which is what
                                          ; suddenly terminates the iterations

【讨论】:

此外,它向 eax 添加 12 而不是 4 的事实表明常量评估认为 y 是 1 而不是 0。 对我来说,它似乎已经执行了循环交换。它是执行 3 次的外部循环。内部循环(y)正在正确执行一次。但是 y 只是取了错误的值。 我可以请您从 A 打印更多值吗?我怀疑它会打印 11,0,0,11,0,0,11,0,0。 @Ajay Brahmakshatriya:是的,它添加 12 的原因相同:它认为内部循环不应该迭代。所以它为外循环的下一次迭代做准备。这毫无意义。 不,我认为它确实意识到内部循环将执行一次。但它只是假设 y 的值错误。不是假设 0,而是假设 1。

以上是关于Visual Studio 2013 中可能存在的 C/C++ 编译器错误的主要内容,如果未能解决你的问题,请参考以下文章

基本字符串操作存在问题 [c+​​+, visual studio 2013]

为啥最小 MFC 项目在 Visual Studio 2013 上存在链接错误?

Visual Studio 2013将不显示Winforms,错误“项目中已存在对组件的引用'系统'

Visual Studio 2013 Reference Hell - 它一直在寻找任何不存在的旧版本的 DLL - 为啥?

如何在 Visual Studio (2013) 中运行 Unity 游戏

在 3.5 而不是 2.0 中编译的类库 - 从 Visual Studio 2008 迁移到 2013