应使用RtlGetVersion而非GetVersionEx,因其直接读取内核版本数据、结果真实可靠;Linux/macOS应使用uname系统调用获取内核版本,需注意编码统一与映射表维护。

Windows下用GetVersionEx还是RtlGetVersion?
GetVersionEx在Windows 8.1之后已被微软标记为废弃,调用它返回的可能是兼容模式下的假版本(比如始终报Windows 8),实际开发中必须避免。推荐改用RtlGetVersion——它不走API转发层,直接读取内核版本数据,结果真实可靠。
注意:RtlGetVersion是NTDLL导出函数,不是kernel32,需手动GetProcAddress获取地址;结构体要用RTL_OSVERSIONINFOW,不是OSVERSIONINFOEX。
// 示例:安全获取Windows真实版本
HMODULE hNtDll = GetModuleHandle(L"ntdll.dll");
if (hNtDll) {
using RtlGetVersionFunc = NTSTATUS(NTAPI*)(PRTL_OSVERSIONINFOW);
auto pRtlGetVersion = (RtlGetVersionFunc)GetProcAddress(hNtDll, "RtlGetVersion");
if (pRtlGetVersion) {
RTL_OSVERSIONINFOW osvi = {0};
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (pRtlGetVersion(&osvi) == STATUS_SUCCESS) {
// osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber
}
}
}
Linux/macOS用uname系统调用最稳妥
uname是POSIX标准接口,跨发行版和macOS都稳定可用,比解析/proc/version或sw_vers命令更轻量、无依赖。
关键点:
立即学习“C++免费学习笔记(深入)”;
-
uname返回的release字段是内核版本(如6.5.0-41-generic),不是发行版版本(如Ubuntu 22.04) - 若需发行版信息,Linux要读
/etc/os-release(需fopen+解析),macOS需执行sw_vers -productVersion(需popen) -
uname不区分大小写,但结构体字段名固定,别手误写成sysname为sysName
#include <sys/utsname.h>
struct utsname un;
if (uname(&un) == 0) {
printf("Sysname: %s\n", un.sysname); // Linux / Darwin
printf("Release: %s\n", un.release); // 内核版本字符串
}
C++跨平台封装要注意std::string编码与内存生命周期
Windows下RtlGetVersion返回宽字符数据,Linux/macOS的uname返回UTF-8字节流,混用std::string存Windows版本号会导致乱码或截断。
建议统一用std::wstring处理Windows路径/版本字符串,对外提供UTF-8接口时再转换(用WideCharToMultiByte或std::wstring_convert——后者C++17已弃用,慎用)。
另一个坑:不要返回局部char[]或临时std::string.c_str()指针,容易悬垂。封装函数应返回值语义的std::string或std::wstring。
别把内核版本当用户感知的“系统版本”
用户说的“Windows 11”或“macOS Sonoma”不是RtlGetVersion或uname能直接给出的——它们只提供底层构建号或内核版。真要匹配营销名称,得自己建映射表:
- Windows:查
dwMajorVersion+dwMinorVersion+dwBuildNumber组合(如10.0.22621 → Windows 11 22H2) - macOS:
uname.release是22.x.x这种XNU版本,需转成Darwin版本,再查对应macOS名称(如Darwin 22 → macOS Ventura) - Linux发行版:
/etc/os-release里的VERSION_ID才是用户认知的版本(如22.04),uname完全无关
这个映射逻辑没法全自动,必须人工维护,而且新系统发布后容易过期。


















