我试图将一个int变量分成任意长度的两个部分(即:将32位分成31和1位,30和2位,16和16位,1和31位等)。
我尝试使用按位移位运算符来实现它,但似乎无法使其正常工作。
int botLength = 4;
int start = ~0;
int top = start << botLength;
int bottom = start - top;
std::cout << "Top: " << std::bitset<32>(top) << std::endl;
std::cout << "Bottom: " << std::bitset<32>(bottom) << std::endl;
此输出
Top: 11111111111111111111111111110000
Bottom: 00000000000000000000000000001111
我想要的地方:
Top: 00001111111111111111111111111111
Bottom: 00000000000000000000000000001111
我认为我可以通过将代码更改为以下内容来解决此问题:
int botLength = 4;
int start = ~0;
int top = start << botLength;
int bottom = start - top;
top = top >> botLength; //added this
std::cout << "Top: " << std::bitset<32>(top) << std::endl;
std::cout << "Bottom: " << std::bitset<32>(bottom) << std::endl;
然而,这似乎添加了1作为填充,因为它输出:
Top: 11111111111111111111111111111111
Bottom: 00000000000000000000000000001111
有人可以建议一种解决方法吗?
答案 0 :(得分:2)
您应该使用uint32_t
等无符号值来解决问题。使变量top
无符号。
变量top
已在您的代码中签名
int botLength = 4;
int start = ~0;
int top = start << botLength;
上面的代码在top
中设置了一个负值,那么最左边的符号位(最高位)是1
。
int bottom = start - top;
top = top >> botLength;
每次向右移动以保持符号后,符号位将再次设置为1
。所以,你有所有位1
。
总之,编译器尝试在每次移位操作后保持有符号整数值的符号。因此,这种机制会影响您的算法,您将无法获得正确的结果。
答案 1 :(得分:2)
因为在C和C ++中int
被视为带符号的数字,所以右移位运算符复制最高有效位,表示符号。签名号码以Two's complement编码。
你应该切换到unsigned
以在向右移动时清除最高位,或者你也可以动态使用强制转换,例如:
unsigned bits = 1;
int s = -1;
s = s >> bits;
int u = -1;
u = unsigned(u) >> bits;
之后,s将为-1(0xFFFFFFFF),而u将为2147483647(0x7FFFFFFF)
答案 2 :(得分:0)
有符号值的最高有效位表示该值是负数还是正数。如M M所示,如果右移一个负数,则操作将符号位扩展为高位。
除以2相当于右移一位。如果你将-4除以2,你会得到-2,而不是6,如果你没有扩展符号,我认为你会得到它。