指针算术Visual Studio C ++

时间:2018-03-01 11:09:38

标签: c++ bitwise-operators pointer-arithmetic

考虑以下两个无用的C ++函数。

使用GCC(4.9.2,32或64位)编译,两个函数都返回与预期相同的值。

使用Visual Studio 2010或Visual Studio 2017(非托管代码)编译,这两个函数都返回不同的值。

我尝试过的事情:

  • 括号,括号,括号
  • 显式转换为char
  • sizeof(char)被评估为1
  • 调试/发布版本
  • 32- / 64-bit

这里发生了什么? 这似乎是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-operator左侧和右侧评估顺序的问题。在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  

1 个答案:

答案 0 :(得分:10)

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

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

(另请注意char可以是signedunsigned。这可能会引入与您类似的代码差异。)