在C++编程中,数据类型的选择不仅影响内存占用和性能,还可以对某些操作的结果产生意想不到的影响。今天,我将分享一个关于C++在不同变量类型下位移操作结果的发现。
位移操作是C++中常见的对整数的高效操作之一。然而,我们可能会忽视一个细节:不同的编译器和数据类型可能会导致位移操作的结果不同。
示例代码
让我们看一个简单的计算512右移n位的代码,来展示这个问题:
#include <iostream>
using namespace std;
int main() {
int L = 512;
for (int i = 0; i < 64; i++) {
cout << L << " >> " << i << " = " << (L >> i) << endl;
}
return 0;
}
在上述代码中,我们使用了一个整数 L
,并尝试对其进行右移操作,观察结果:
512>>0 = 512
512>>1 = 256
512>>2 = 128
512>>3 = 64
512>>4 = 32
512>>5 = 16
512>>6 = 8
……
512>>30 = 0
512>>31 = 0
512>>32 = 512
512>>33 = 256
512>>34 = 128
……
发现
我天真地以为,只要右移的位数超出范围,结果为0。
但实际结果让我出乎意料:当 i
的值达到 32 时,512 >> 32
的结果变成了 512,然后往后,512 >> 33
等于 256,512 >> 34
等于 128,如此类推。
这与Python的计算表现完全不同。Python的运算结果是,只要超出范围,结果永远为零。
这意味着,当 i
大于等于 32 时,C / C++的右移操作不再产生预期的结果,而是保持原始值,这将严重影响后续的运算结果。
解决方案
为了解决这个问题,我们尝试将 L
的数据类型更改为 long
,但很遗憾结果与使用 int
类型的情况一样,仍然无法得到正确的结果。
最后,我将 L
的类型更改为 long long
,才得出了预期的结果。
#include <iostream>
using namespace std;
int main() {
// 把L的类型由int改为long long
long long L = 512;
for (int i = 0; i < 64; i++) {
cout << L << " >> " << i << " = " << (L >> i) << endl;
}
return 0;
}
运行结果截图
2023年10月5日更新
解决方法二:使用std::bitset
。
std::bitset<32>
是C++标准库中的一个固定大小的数据类型,它包含了32个二进制位,无法动态调整大小。这意味着无论如何,std::bitset<32>
都将保持32位的大小。
#include <iostream>
#include <bitset>
using namespace std;
int main() {
int L1 = 512;
bitset<32> L2(L1); // 创建了一个包含32位的位集合,并将其初始化为512
for(int i=0; i<=100; i++){
cout << (L2>>i).to_ulong() << endl;
}
return 0;
}