c - 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 中运行这个函数时,它给出了一个意想不到的答案。输入x
为0xffffffff
( -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 中有什么不同会导致这个问题吗?
解决方案
根据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。
您正在对有符号整数值进行位移。根据您的输入,您取决于未定义和实现定义的行为。
在不同的平台上会有不同的结果是可以预料的。
推荐阅读
- nunit - NUnit/TeamCity 进程退出,代码为 -4
- java - 如何显示带有值的休眠 sql 参数,而不是?,?
- sql - 与另一个表的不同条件求和
- c# - 无法从 .aspx 页面访问代码隐藏变量
- facebook - 用于潜在客户检索的 Webhook:可以对单个应用程序使用多个回调吗?
- javascript - Angular 应用无法在 Firefox 和 Safari 上运行
- logging - 坚持尝试通过 google-fluentd.conf 自定义堆栈驱动程序的日志实体
- c# - 从 v7 升级到 v9 后 Automapper 不起作用
- java - Spring @EnableScheduling 和 @Schedule 注释不起作用
- julia - 从另一个 DataFrame 中提取单独的分组 DataFrame