1.背景
2018 上半年折腾了一回,想换个后台开发岗锻炼一下自己。我在腾讯内部转岗遇到了这道面试题,特此记录下来。
2.问题
我们知道在 C/C++ 中使用运算符 sizeof 计算指针变量的大小,如果返回值为 4 字节则是 32 位,如果返回 8 字节,则表示 64 位系统。
现在要求不使用 sizeof 如何判断操作系统是 32 位还是 64 位。
3.解法
3.1 解法一:整型最大值溢出
我们知道 C/C++中,32 位系统下编译生成的程序,整型数值默认取值范围是 − 2 31 -2^{31} −231 至 2 31 − 1 2^{31}-1 231−1,加上数值后缀 L,表示长整型,取值范围也是 − 2 31 -2^{31} −231 至 2 31 − 1 2^{31}-1 231−1,加上 LL 表示长长整型数值,取值范围是 − 2 63 -2^{63} −263 至 2 63 − 1 2^{63}-1 263−1。
64 位系统下编译生成的 64 位程序(为什么指明说 64 位的程序,因为 64 系统下也可以编译生成32的位的程序),整型数值默认取值范围是 − 2 31 -2^{31} −231 至 2 31 − 1 2^{31}-1 231−1,加上数值后缀 L,表示长整型,取值范围也是 − 2 63 -2^{63} −263 至 2 63 − 1 2^{63}-1 263−1,加上 LL 表示长长整型数值,取值范围是 − 2 63 -2^{63} −263 至 2 63 − 1 2^{63}-1 263−1。
所以根据数值后缀 L 可以判断系统是 32 位还是 64 位,实际上我们是利用整型最大值是否溢出情况来做判断。
#include <iostream>
using namespace std;
int main() {
long ldTmp = 1L<<32;
cout << "sizeof(long):" << sizeof(long) << endl;
cout << "ldTmp:" << ldTmp << endl;
if(ldTmp) {
cout<<"64 bits"<<endl;
} else {
cout<<"32 bits"<<endl;
}
}
使用g++ -m64 main.cpp -o a64.out
生成 64 位程序输出结果为:
sizeof(long):8
ldTmp:4294967296
64 bits
使用g++ -m32 main.cpp -o a32.out
生成32位程序输出结果为:
sizeof(long):4
ldTmp:0
32 bits
3.2 解法二:__WORDSIZE
Linux 环境下,可以根据 GNU C 库的头文件 wordsize.h 中定义的宏 __WORDSIZE 来判断。wordsize.h 路径一般为 /usr/include/bits/wordsize.h,其内容如下:
/* Determine the wordsize from the preprocessor defines. */
#if defined __x86_64__
# define __WORDSIZE 64
# define __WORDSIZE_COMPAT32 1
#else
# define __WORDSIZE 32
#endif
判断代码如下:
#include <bits/wordsize.h>
#include <iostream>
using namespace std;
int main() {
#if __WORDSIZE == 64
cout << "64bits" << endl;
#else
cout << "32bits" << endl;
#endif
}
类似的方法,在 limits.h 头文件中,包含了头文件 wordsize.h 后,根据 __WORDSIZE 做了如下相关宏定义:
/* Maximum value an `unsigned long int' can hold. (Minimum is 0.) */
# if __WORDSIZE == 64
# define ULONG_MAX 18446744073709551615UL
# else
# define ULONG_MAX 4294967295UL
# endif
所以,根据如下代码也可以判断程序是 32 位还是 64 位。
#include <limits.h>
#include <iostream>
using namespace std;
int main() {
#if ULONG_MAX==0xFFFFFFFFFFFFFFFFUL
cout << "64bits" << endl;
#else
cout << "32bits" << endl;
#endif
}
3.3 解法三:指针变量位宽
根据栈指针变量宽度来判断,感谢腾讯 blitzhong 同学的提示。对指针变量地址相减时,须将其转换为 char* 或无符号长整型(unsigned long),否则相减的结果为 1,表示地址间隔内存放元素的个数。
#include <iostream>
using namespace std;
int main() {
void* a;
void* b;
int scope = (char*)&a - (char*)&b;
cout << "&a:" << &a << endl;
cout << "&b:" << &b << endl;
cout << "scope:" << scope << endl;
if(scope==8) {
cout << "64bits" << endl;
} else {
cout << "32bits" << endl;
}
}
使用g++ -m64 main.cpp -o a64.out
编译执行输出:
&a:0x7fffcc84b650
&b:0x7fffcc84b648
scope:8
64bits
使用g++ -m32 main.cpp -o a32.out
编译执行输出:
&a:0xffbb42e8
&b:0xffbb42e4
scope:4
32bits
如果网友有其他方法,也请留言告知,万分感谢!