我正在尝试做一种左移,它会在开头添加零而不是一。例如,如果我左移 0xff
,我会得到:
0xff << 3 = 11111000
但是,如果我右移它,我会得到:
0xff >> 3 = 11111111
我可以使用任何操作来获得相当于左移的操作吗?即我想得到这个:
00011111
有什么建议吗?
编辑
为了回答评论,这是我正在使用的代码:
int number = ~0;
number = number << 4;
std::cout << std::hex << number << std::endl;
number = ~0;
number = number >> 4;
std::cout << std::hex << number << std::endl;
输出:
fffffff0
ffffffff
由于它似乎通常应该起作用,我对为什么这个特定代码不起作用感兴趣。任何想法?
原文由 laurent 发布,翻译遵循 CC BY-SA 4.0 许可协议
这就是 C 和二进制算术的工作原理:
如果你左移
0xff << 3
,你会得到二进制:00000000 11111111 << 3 = 00000111 11111000
如果你右移
0xff >> 3
,你会得到二进制:00000000 11111111 >> 3 = 00000000 00011111
0xff
是一个(有符号的)int,其值为正值255
。由于它是正数,因此转换它的结果是 C 和 C++ 中定义明确的行为。它不会做任何算术移位,也不会做任何种类或定义不明确的行为。输出:
所以你在你的程序中做了一些奇怪的事情,因为它没有按预期工作。也许您正在使用 char 变量或 C++ 字符文字。
来源:ISO 9899:2011 6.5.7。
问题更新后编辑
int number = ~0;
给你一个等于-1的负数,假设二进制补码。number = number << 4;
调用未定义的行为,因为您左移了一个负数。该程序正确地实现了未定义的行为,因为它要么做某事,要么什么都不做。它可能会打印 fffffff0 或者可能会打印粉红色的大象,或者它可能会格式化硬盘驱动器。number = number >> 4;
调用实现定义的行为。在您的情况下,您的编译器会保留符号位。这称为 算术移位,算术右移以这样一种方式工作,即 MSB 用移位前的任何位值填充。因此,如果您有一个负数,您将体验到该程序正在“移入”。在现实世界中 99% 的情况下,对有符号数使用位运算符是没有意义的。因此,请始终确保您使用的是无符号数,并且 C/C++ 中没有任何危险的隐式转换规则将它们转换为有符号数(有关危险转换的更多信息,请参阅“整数提升规则”和“通常的算术转换”,关于 SO 的大量好信息)。
编辑 2 ,来自 C99 标准的基本原理文档 V5.10 的一些信息: