指针运算Visual Studio C++
Pointer arithmetic Visual Studio C++
考虑以下两个无用的 C++ 函数。
使用 GCC(4.9.2、32 位或 64 位)编译,这两个函数返回与预期相同的值。
使用 Visual Studio 2010 或 Visual Studio 2017(非托管代码)编译,两个函数返回不同的值。
我尝试过的:
- 括号,括号,括号
- 显式转换为 char
- sizeof(char) 计算为 1
- 调试/发布版本
- 32/64 位
这是怎么回事? 这似乎是 VS 中的一个基本错误。
char test1()
{
char buf[] = "The quick brown fox...", *pbuf = buf;
char value = (*(pbuf++) & 0x0F) | (*(pbuf++) & 0xF0);
return value;
}
char test2()
{
char buf[] = "The quick brown fox...", *pbuf = buf;
char a = *(pbuf++) & 0x0F;
char b = *(pbuf++) & 0xF0;
char value = a | b;
return value;
}
编辑:
- 这不是试图指责 VS(如帖子中所述)。
- 这不是签名或未签名的问题。
- 这不是 or 运算符左右两侧的求值顺序问题。更改 test2() 中 a 和 b 的赋值顺序会产生第三个结果。
- 但同时性是个好点。似乎评估的顺序被定义为未定义。第一步,生成的代码计算 test1() 中的完整表达式,而不增加任何指针。在第二步中,指针将递增。由于自增没有效果,在这个特定操作后数据保持不变,优化器将删除代码。
抱歉给您带来不便,但这不是我所期望的。没有语言。
为了完整起见,这里是test1()的反汇编代码:
0028102A mov ecx,dword ptr [ebp-8]
0028102D movsx edx,byte ptr [ecx]
00281030 and edx,0Fh
00281033 mov eax,dword ptr [ebp-8]
00281036 movsx ecx,byte ptr [eax]
00281039 and ecx,0F0h
0028103F or edx,ecx
00281041 mov byte ptr [ebp-1],dl
00281044 mov edx,dword ptr [ebp-8]
00281047 add edx,1
0028104A mov dword ptr [ebp-8],edx
0028104D mov eax,dword ptr [ebp-8]
00281050 add eax,1
00281053 mov dword ptr [ebp-8],eax
(*(pbuf++) & 0x0F) | (*(pbuf++) & 0xF0);
的行为是未定义。 |
(与 ||
不同) 不是 排序点,因此您可以在同一程序步骤中同时读取和写入 pbuf
。
因此不是 VS 错误。 (这样的事情很少见:黄金法则是不要责怪编译器。)
(另请注意,char
可以是 signed
或 unsigned
。这会像您的代码一样引入差异。)
考虑以下两个无用的 C++ 函数。
使用 GCC(4.9.2、32 位或 64 位)编译,这两个函数返回与预期相同的值。
使用 Visual Studio 2010 或 Visual Studio 2017(非托管代码)编译,两个函数返回不同的值。
我尝试过的:
- 括号,括号,括号
- 显式转换为 char
- sizeof(char) 计算为 1
- 调试/发布版本
- 32/64 位
这是怎么回事? 这似乎是 VS 中的一个基本错误。
char test1()
{
char buf[] = "The quick brown fox...", *pbuf = buf;
char value = (*(pbuf++) & 0x0F) | (*(pbuf++) & 0xF0);
return value;
}
char test2()
{
char buf[] = "The quick brown fox...", *pbuf = buf;
char a = *(pbuf++) & 0x0F;
char b = *(pbuf++) & 0xF0;
char value = a | b;
return value;
}
编辑:
- 这不是试图指责 VS(如帖子中所述)。
- 这不是签名或未签名的问题。
- 这不是 or 运算符左右两侧的求值顺序问题。更改 test2() 中 a 和 b 的赋值顺序会产生第三个结果。
- 但同时性是个好点。似乎评估的顺序被定义为未定义。第一步,生成的代码计算 test1() 中的完整表达式,而不增加任何指针。在第二步中,指针将递增。由于自增没有效果,在这个特定操作后数据保持不变,优化器将删除代码。
抱歉给您带来不便,但这不是我所期望的。没有语言。
为了完整起见,这里是test1()的反汇编代码:
0028102A mov ecx,dword ptr [ebp-8]
0028102D movsx edx,byte ptr [ecx]
00281030 and edx,0Fh
00281033 mov eax,dword ptr [ebp-8]
00281036 movsx ecx,byte ptr [eax]
00281039 and ecx,0F0h
0028103F or edx,ecx
00281041 mov byte ptr [ebp-1],dl
00281044 mov edx,dword ptr [ebp-8]
00281047 add edx,1
0028104A mov dword ptr [ebp-8],edx
0028104D mov eax,dword ptr [ebp-8]
00281050 add eax,1
00281053 mov dword ptr [ebp-8],eax
(*(pbuf++) & 0x0F) | (*(pbuf++) & 0xF0);
的行为是未定义。 |
(与 ||
不同) 不是 排序点,因此您可以在同一程序步骤中同时读取和写入 pbuf
。
因此不是 VS 错误。 (这样的事情很少见:黄金法则是不要责怪编译器。)
(另请注意,char
可以是 signed
或 unsigned
。这会像您的代码一样引入差异。)