Visual Studio 2013 中可能存在 C/C++ 编译器错误
Possible C/C++ compiler bug in Visual Studio 2013
以下 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;
}
是的,这似乎是一个编译器错误。在 Win32 版本的代码中,编译器使用寄存器 esi
来表示 y
并使用寄存器 edx
来表示 x
。正如 @Ajay Brahmakshatriya 在评论中正确指出的那样,编译器似乎尝试交换循环(将外部与内部交换),但最终代码不正确。最后一条条件跳转指令,应该代表 [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
以下 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;
}
是的,这似乎是一个编译器错误。在 Win32 版本的代码中,编译器使用寄存器 esi
来表示 y
并使用寄存器 edx
来表示 x
。正如 @Ajay Brahmakshatriya 在评论中正确指出的那样,编译器似乎尝试交换循环(将外部与内部交换),但最终代码不正确。最后一条条件跳转指令,应该代表 [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