C++ 如何跨平台判斷操作系統是32位還是64位?
1、判斷操作系統位數,不是判斷編譯器,也不是判斷cpu;
2、不調用操作系統API,要求跨平台判斷。
3、如果可以順便解釋下原理,以及為什麼;
自己通過sizeof判斷,不準確,估計是跟編譯器有關。
判斷來幹嘛。你一個32位程序,運行在64位的Windows裡面,API就欺騙你了,讓你覺得周圍的一切全部都是32位的。你直接去讀CPU的型號和Windows的版本信息吧。
說到版本的問題,根據微軟的尿性,每一個版本的Windows都有一個全新的閱讀Windows版本的方法,也就是說,這相當於你只能辨別你寫程序的時候已經存在的Windows版本,同時也相當於更高版本的Windows都會欺騙你說它是你當初知道的最新的那個版本。
這裡提供另一種思路,來自於cmake。
cmake在檢測編譯器的時候,用了一種很暴力的方法。可以在不運行實際代碼的情況下直接知道目標平台的信息。做法是這樣的。
首先生成一個.cpp文件,包含一些平台檢測的#ifdef
/* Identify known platforms by name. */
#if defined(__linux) || defined(__linux__) || defined(linux)
# define PLATFORM_ID "Linux"
#elif defined(__CYGWIN__)
# define PLATFORM_ID "Cygwin"
#elif defined(__MINGW32__)
# define PLATFORM_ID "MinGW"
#elif defined(__APPLE__)
# define PLATFORM_ID "Darwin"
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
# define PLATFORM_ID "Windows"
#elif defined(__FreeBSD__) || defined(__FreeBSD)
# define PLATFORM_ID "FreeBSD"
...
以及架構檢測的#ifdef
#if defined(_WIN32) defined(_MSC_VER)
# if defined(_M_IA64)
# define ARCHITECTURE_ID "IA64"
# elif defined(_M_X64) || defined(_M_AMD64)
# define ARCHITECTURE_ID "x64"
# elif defined(_M_IX86)
# define ARCHITECTURE_ID "X86"
# elif defined(_M_ARM64)
# define ARCHITECTURE_ID "ARM64"
# elif defined(_M_ARM)
# if _M_ARM == 4
# define ARCHITECTURE_ID "ARMV4I"
# elif _M_ARM == 5
# define ARCHITECTURE_ID "ARMV5I"
# else
# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
# endif
# elif defined(_M_MIPS)
# define ARCHITECTURE_ID "MIPS"
# elif defined(_M_SH)
# define ARCHITECTURE_ID "SHx"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#elif defined(__WATCOMC__)
# if defined(_M_I86)
# define ARCHITECTURE_ID "I86"
# elif defined(_M_IX86)
# define ARCHITECTURE_ID "X86"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#else
# define ARCHITECTURE_ID
#endif
之後,定義兩個char const*常量。
char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";
然後把這個cpp編譯成二進位。你以為要運行它?不是的。對於交叉編譯的情況來說,目標平台的二進位是沒法在編譯平台上運行的。所以cmake用了一招更狠的,直接打開二進位文件,搜索字元串。
比如在Windows x64平台上,剛才那兩個常量就會被編譯成INFO:platform[Windows]和INFO:arch[x64]。而這樣的字元串,一定是存在於二進位文件里的。所以只要搜索INFO:platform,後面[]里的就是平台;搜索INFO:arch,後面[]里的就是架構。
同理,cmake里還有對編譯器和編譯器版本等信息的檢測,都是這麼來的。
並沒有什麼真正通用的辦法可以判斷,你只能根據流行的系統的特點一個一個試。
對Windows:
- 你自己的code是64位的,那你的系統當然是64位的
- 你的code是32位的情況下,有個東西叫IsWow64Process。這東西如果不存在或者返回false,那就是32位系統,否則就是64位系統。
對Linux/BSD等*NIX系統:
- 直接開個管道調用uname,他會把內核情況一五一十說清楚。
其他的自己Google吧。
PS:以上還只是針對x86.x64系統。如果考慮到ARMv7和ARMv8,還要自己再查一查。
假如你編譯了一個 32 位 Windows 程序,它在 64 位 Windows 上跑仍然是以 32 位兼容模式運行的,sizeof() 就不對了,它只是檢測編譯平台,而不是運行平台。
如果你用 Qt,這裡有一個很便利的類 QSysInfo,用裡面的 currentCpuArchitecture() 方法:
QSysInfo Class | Qt Core 5.8
操作系統會騙你,所以不存在通用方法
既然你只說跨平台,沒說跨編譯器,而且還必須不用系統API,那麼你能用的就只有編譯器提供的預編譯宏了,你自己去翻翻你用的編譯器的文檔就有了。
至於原理,大致上就是編譯器在安裝/編譯時就幫你判斷好了,然後你在代碼里就可以通過宏開關來判斷了。
如果還想問編譯器是怎麼判斷的?雖然我不十分確定,但估計那多半是調用系統API吧?
請不要把編譯器的鍋甩給 cpp
另外 cpp 跨平台的方法是每個平台都編譯一次,如果不想多次變異的話,請走 Java 的邪道首先,除了386和amd64之外還有其它架構。
接著假設你題中意思是指的編譯完的程序進行判斷。最後下結論,既不能判斷CPU,又不能調API,那隻能跟你說,沒有辦法了。sizeof是個常數,編譯期就定了,不可能隨著系統變化而變化。當然如果是源碼,那編譯器宏或者sizeof(size_t)就完了。我感覺是無解的,看了一下各種回答也不符合題主描述。實際工程中跨平台都是用宏定義之類編譯期判斷編譯器和目標平台
你說的是操作系統,64位可以運行32位程序,因此sizeof是沒法判斷的。跨平台要是cpu也要跨的話,沒辦法判斷。即便限定x86cpu,也很難判斷。
通過判斷指針的位元組數,sizeof(char*)。
題主你這問題,成心折騰程序員。。
首先得說明一下,不調用系統API,又想知道與系統相關的東西,這就像你讓我進門拿東西,又把門鎖上不給我鑰匙一樣,正統方法是根本不可能做到的(且不深究這麼做有什麼意義,本來一個很簡單的函數就能解決的問題繞個圈)。那就得走曲道破窗而入。
其次是跨平台不是語言本身的功能,是人為去調配的,根據已知的一些信息,去把這個開關拔到win或是linux一端(或其他)。
然後sizeof指令是編譯平台相關的,他不是由當前操作系統的位數決定的,而是由通過編譯器期望生成的可執行文件運行的操作系統決定的,即比如:我編譯器設置好目標的平台是64位win10,那麼sizeof求出來的位元組就和64位win10相匹配。
最後提供曲線進屋方案:
跨平台方法,由宏決定,win下關鍵宏_WIN32等等,linux關鍵宏linux;
操作系統位數判斷方法提供一個不穩定方案:由於64位系統與32位系統在系統文件及系統文件夾上有所不同,由此可以進行對比判斷,如:win平台判斷系統根目錄有無program files(x86)文件夾來判斷,要是不保險可以多找幾個來判斷,同理linux下可以判斷有無/lib64來判斷。。
你只能通過宏知道你的程序是幾位的,高位的操作系統一般都可以有低位的子系統,不用系統 API 的話那隻能做夢了。
要判斷是32還是64位,要分兩個步驟,1)這是哪個操作系統,2)是32位還是64位。
1)這是哪個操作系統。
哪個系統是要靠編譯器去判斷,API、sizeof都是不靠譜的。(https://github.com/freeors/SDL/blob/master/SDL2-2.0.5/include/SDL_platform.h),這個*.h是SDL工程一部分,裡面有各種編譯器判斷。以下我解釋下windows、macosx、iOS和android。
Microsoft Windows
================================
_WIN32:Microsoft 32位/64位 C/C++編譯器內置定義。
_WIN64:Microsoft 64位 C/C++編譯器內置定義。
編譯器內置了兩個宏定義,程序使用時不必包含任何必須的頭文件。
--------------------------------
經常能看到WIN32、_WINDOWS,這些是Visual Studio在創建工程後給的默認定義,不能作為Windows的標準定義。
Apple Mac OS X
================================
__APPLE__:Apple C/C++編譯器內置定義。
Apple iOS
================================
__APPLE__:Apple C/C++編譯器內置定義。
TARGET_OS_IPHONE:TargetConditionals.h內定義。iOS(包括iPad/iPhone/iTouch)真機及模擬器。
TARGET_IPHONE_SIMULATOR:TargetConditionals.h內定義。只針對iOS模擬器。
註:TARGET_OS_IPHONE、TARGET_IPHONE_SIMULATOR是宏,但在Mac OS X這兩個宏也是存在的,只不過值是0!
--------------------------------------------------
Apple C/C++只內置__APPLE__宏定義,但Mac OS X和iOS都定義了這宏,那要如何區分是OS X還是iOS?——使用TARGET_OS_IPHONE宏。程序要滿足「#if defined(__APPLE__) TARGET_OS_IPHONE」時認為是iOS系統。
但TARGET_OS_IPHONE是在TargetConditionals.h內定義的,要使用該宏則必須先#include &
#if defined(__APPLE__)
#include &
#if TARGET_OS_IPHONE
放置iOS代碼
#else
放置OS X代碼
#endif
#endif
Android
================================
ANDROID:Android GCC編譯器內置定義。
編譯器內置了此個宏定義,程序使用時不必包含任何必須的頭文件。
2)是32位還是64位。
Windows
================================
https://github.com/freeors/SDL/blob/master/SDL2-2.0.5/include/SDL_config_windows.h
看有沒有定義_WIN64
Apple Mac OS X
================================
https://github.com/freeors/SDL/blob/master/SDL2-2.0.5/include/SDL_config_macosx.h
看有沒有定義__LP64__
Apple iOS
================================
https://github.com/freeors/SDL/blob/master/SDL2-2.0.5/include/SDL_config_iphoneos.h
看有沒有定義__LP64__
Android
================================
https://github.com/freeors/SDL/blob/master/SDL2-2.0.5/include/SDL_config_android.h
雖然CPU有32位和64位,但目前代碼上還真沒啥好招
#ifdef __i386 32#else 64#endif
就不能先google一下么
判斷宏 _LP64
這個問題同C++沒什麼關係. 你沒有說清楚是運行時還是編譯期判斷, 兩者不同
1. 編譯期
編譯器會告訴目標平台的架構
sizeof是編譯器的常量
2. 運行期
程序當然知道是什麼平台, 因為不同CPU有不同的指令集, 一個二進位程序不能跨平台運行(x86程序不能運行在powerpc上)
同一個平台的64位cpu一般會兼容32位程序, 你可以判斷一個32位的程序是否運行在64位cpu的Compatibility 模式下.
你不想使用系統調用. 就linux來說, 一種方式是利用32位程序在64位機器上的虛擬地址空間同真正32位CPU上的不同. Compatibility 模式下程序可用的地址空間接近4G, 但是32位機器上因為內核空間佔用, 只能用2~3G
寫程式的時候不要使用魔法數字(magical number)就行,用sizeof()代替4,8這樣的
好像有一個TCP/IP服務可以告訴你現在是什麼平台多少位主機。
推薦閱讀:
※在鏈表中應該用哪種智能指針比較合理?
※什麼時候適合使用 C++ 而不是 C?
※除了emoji,有沒有用utf16兩個位元組表示不了而且現代文章/姓名中會使用的cjkv字元么?
※c++如何做設計?或者推薦一些比較簡單的開源項目,適合新手練手的。