首页 > 解决方案 > macOS 10.12 中 C 语言的位右移与 Ubuntu 16.04 不同

问题描述

更新:我只是在 macOS 上的一个新的 C 源文件中重写了该函数:

#include <stdio.h>

int main() {

int x = 0xffffffff;

int m2 = (((((0x55 << 8) + 0x55 )<< 8) + 0x55)<< 8) + 0x55;
printf("m2 : 0x%x\n",m2);

int m4 = (((((0x33 << 8) + 0x33 )<< 8) + 0x33)<< 8) + 0x33;
printf("m4 : 0x%x\n",m4);

int m8 = (((((0x0f << 8) + 0x0f )<< 8) + 0x0f)<< 8) + 0x0f;
printf("m8 : 0x%x\n",m8);

int m16 = (0xff << 16) + 0xff ;
printf("m16 : 0x%x\n",m16);

int p1 = (x & m2) + ((x >> 1) & m2);
printf("p1: 0x%x\n",p1);

printf("p1 & m4 : 0x%x\n",p1 & m4);

printf("p1 >> 2 : 0x%x\n",p1 >> 2);

printf("(p1 >> 2) & m4 : 0x%x\n",(p1 >> 2) & m4);

int p2 = (p1 & m4) + ((p1 >> 2) & m4);
printf("p2 : 0x%x\n",p2);

int p3 = (p2 & m8) + ((p2 >> 4) & m8) ;
printf("p3 : 0x%x\n",p3);

int p4 = (p3 & m16)  + ((p3 >> 8) & m16) ;
printf("p4 : 0x%x\n",p4);
//int p4 = p3   + (p3 >> 8)  ;
int p5 = p4 + (p4 >> 16) ;

printf("BigCount result is : 0x%x\n",p5 & 0xFF);
}

打印结果是: 在此处输入图像描述

一切都与 Ubuntu 中的相同。这让我更加困惑。


当我在 macOS 10.12 中运行这个函数时,它给出了一个意想不到的答案。输入x0xffffffff( -1)。该函数是用 C 语言编写的:

int bitCount(int x) {

  int m2 = (((((0x55 << 8) + 0x55 )<< 8) + 0x55)<< 8) + 0x55;
  int m4 = (((((0x33 << 8) + 0x33 )<< 8) + 0x33)<< 8) + 0x33;
  int m8 = (((((0x0f << 8) + 0x0f )<< 8) + 0x0f)<< 8) + 0x0f;
  int m16 = (0xff << 16) + 0xff ;

  int p1 = (x & m2) + ((x >> 1) & m2);
  int p2 = (p1 & m4) + ((p1 >> 2) & m4); //line 7
  int p3 = (p2 & m8) + ((p2 >> 4) & m8) ;
  int p4 = (p3 & m16)  + ((p3 >> 8) & m16) ;
  //int p4 = p3   + (p3 >> 8)  ;
  int p5 = p4 + (p4 >> 16) ;

  return p5 & 0xFF;
}

当我通过打印跟踪所有局部变量时,我发现:

((p1 >> 2) & m4) //line7

打印'0x2222222'的值(七个'2'而不是八个'2')。 在此处输入图像描述

这太出乎意料了,p1打印'0x2aaaaaaa'而m4是'0x33333333',所以它应该是0x22222222(八个'2;)。但是,当我在 ubuntu 16.04 中运行它时,一切都和预期的一样,因为 ((p1 >> 2) & m4) 打印 '0x22222222': 在此处输入图像描述

你在你的Mac上运行这个有同样的问题吗?macOS 中有什么不同会导致这个问题吗?

标签: cmacosubuntu-16.04bit

解决方案


根据C 标准的6.5.7 位移位运算符(注意突出显示的部分):

约束

2 每个操作数应为整数类型。

语义

3 对每个操作数执行整数提升。结果的类型是提升的左操作数的类型。如果右操作数的值为负数或大于或等于提升的左操作数的宽度,则行为未定义。

4 E1 << E2的结果是E1左移E2位;空出的位用零填充。如果 E1 具有无符号类型,则结果的值为 E1 x 2E2 ,以比结果类型中可表示的最大值多一个模数减少。如果 E1 具有带符号类型和非负值,并且 E1 x 2E2 在结果类型中是可表示的,那么这就是结果值;否则,行为是 undefined

5 E1 >> E2 的结果是 E1 右移 E2 位位置。如果 E1 具有无符号类型或 E1 具有有符号类型和非负值,则结果的值是 E1 / 2E2 的商的整数部分。如果 E1 具有带符号类型和负值,则结果值是 implementation-defined

您正在对有符号整数值进行位移。根据您的输入,您取决于未定义和实现定义的行为。

在不同的平台上会有不同的结果是可以预料的。


推荐阅读