lau*_*ent 7 c c++ bit-manipulation bit-shift
我正在尝试做一种左移,在开头添加零而不是一些.例如,如果我离开0xff,我得到这个:
0xff << 3 = 11111000
Run Code Online (Sandbox Code Playgroud)
但是,如果我改变它,我得到这个:
0xff >> 3 = 11111111
Run Code Online (Sandbox Code Playgroud)
我可以使用任何操作来获得相当于左移的功能吗?即我想得到这个:
00011111
Run Code Online (Sandbox Code Playgroud)
有什么建议吗?
编辑
要回答评论,这里是我正在使用的代码:
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;
Run Code Online (Sandbox Code Playgroud)
输出:
fffffff0
ffffffff
Run Code Online (Sandbox Code Playgroud)
因为它似乎总体上应该有效,所以我对这个特定代码没有的原因感兴趣.任何的想法?
Lun*_*din 10
这就是C和二进制算法的工作原理:
如果你离开了0xff << 3,你得到二元:00000000 11111111 << 3 = 00000111 11111000
如果你右转0xff >> 3,你得到二进制:00000000 11111111 >> 3 = 00000000 00011111
0xff是具有正值的(带符号)int 255.由于它是积极的,因此转移它的结果是C和C++中明确定义的行为.它不会进行任何算术转换,也不会进行任何类型或定义不明确的行为.
#include <stdio.h>
int main()
{
printf("%.4X %d\n", 0xff << 3, 0xff << 3);
printf("%.4X %d\n", 0xff >> 3, 0xff >> 3);
}
Run Code Online (Sandbox Code Playgroud)
输出:
07F8 2040
001F 31
Run Code Online (Sandbox Code Playgroud)
所以你在程序中做了一些奇怪的事情,因为它没有按预期工作.也许你正在使用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的一些信息:
6.5.7按位移位运算符
K&R中移位运算符的描述表明,通过长计数移位应该强制左操作数在移位之前加宽.由C89委员会认可的更直观的做法是,班次计数的类型与结果的类型无关.
C89的安静改变
通过长计数移动不再强制将移位的操作数强制为长.C89委员会肯定了K&R授予的实施自由,不要求签署权利转移操作签署延期,因为这样的要求可能会减慢快速代码的速度,并且因为符号扩展班次的有用性是微不足道的.(在一个地方算术右移一个负2的补数整数与除以2的不一样!)
如果你明确地移动0xff它就像你期望的那样工作
cout << (0xff >> 3) << endl; // 31
Run Code Online (Sandbox Code Playgroud)
只有0xff在签名宽度为8的类型(char以及signed char流行的平台上)时才应该这样.
所以,在一般情况下:
您需要使用无符号整数
(unsigned type)0xff
右移作为2除法(如果我理解正确的话,向下舍入).
所以当你有1作为第一位时,你有负值,而在除法后它再次为负.