指针算术Visual Studio C++

Qyl*_*yle 1 c++ bitwise-operators pointer-arithmetic

考虑以下两个无用的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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

  • 这不是企图责怪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  
Run Code Online (Sandbox Code Playgroud)

Bat*_*eba 10

行为(*(pbuf++) & 0x0F) | (*(pbuf++) & 0xF0);未定义的.|(与之不同||)不是一个排序点,因此您可以pbuf在同一个程序步骤中同时进行读写操作.

因此不是VS的错误.(这样的事情很少:黄金法则不应该责怪编译器.)

(另请注意,char可以是signed或者unsigned.这可能会引入与您类似的代码差异.)

  • @ Cheersandhth.-Alf:我也可以将标准链接起来(任何C++问题的重复目标),但这不会让我谈论VS bug部分. (3认同)