应使用RtlGetVersion获取真实系统版本,因其不走兼容层、无需manifest声明;VerifyVersionInfo虽可用但需构造OSVERSIONINFOEX并受manifest限制,且Windows 8.1后默认返回降级版本号(如6.2)。

Windows下用GetVersionEx已弃用,改用VerifyVersionInfo或RtlGetVersion
直接调用GetVersionEx在Windows 8.1之后会返回固定值(如Windows 8),无法识别Win10/Win11。微软明确标记该API为deprecated,且部分新系统可能直接失败。
推荐方案是RtlGetVersion(无需manifest,兼容性好)或VerifyVersionInfo(需构造OSVERSIONINFOEX结构并调用两次)。前者更轻量:
#include <windows.h>
#include <iostream>
<p>void GetWindowsVersion() {
OSVERSIONINFOEXW osvi = {};
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (RtlGetVersion((LPOSVERSIONINFOW)&osvi) == 0) {
std::wcout << L"Windows " << osvi.dwMajorVersion << L"."
<< osvi.dwMinorVersion << L"." << osvi.dwBuildNumber << L"
";
}
}
-
RtlGetVersion是ntdll.dll导出函数,需链接ntdll.lib或手动GetProcAddress - 返回的
dwMajorVersion/dwMinorVersion仅反映内核版本,不是UI显示名(如“Windows 11”) - 要获取完整产品名称(如“Windows 11 Pro”),必须查注册表:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName
Linux下读取/etc/os-release最可靠
POSIX标准不提供统一API获取发行版名称,uname()只返回内核版本(如5.15.0-107-generic),不能识别Ubuntu/CentOS等发行版。
现代Linux发行版遵循os-release规范,应优先解析/etc/os-release:
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
#include <fstream>
#include <string>
#include <map>
<p>std::string GetLinuxDistroName() {
std::ifstream f("/etc/os-release");
std::string line, key, value;
std::map<std::string, std::string> props;
while (std::getline(f, line)) {
size_t eq = line.find('=');
if (eq != std::string::npos) {
key = line.substr(0, eq);
value = line.substr(eq + 1);
if (value.size() > 2 && value.front() == '"' && value.back() == '"') {
value = value.substr(1, value.size() - 2);
}
props[key] = value;
}
}
return props["PRETTY_NAME"];
}
- 不要依赖
/etc/redhat-release或/etc/lsb-release,它们非标准且可能不存在 -
PRETTY_NAME字段是用户友好的完整名称(如“Ubuntu 22.04.4 LTS”);NAME较简略(如“Ubuntu”) - 注意字符串转义:值可能带双引号、反斜杠,需按规范解码
macOS需组合sysctl和sw_vers命令
uname()在macOS返回Darwin内核名,sysctl kern.osrelease给的是XNU版本(如23.5.0),都不是用户认知的“macOS Sonoma”。
Apple未提供稳定C API,唯一可靠方式是执行sw_vers命令并解析输出:
#include <cstdlib>
#include <array>
#include <string>
<p>std::string GetMacOSVersion() {
std::array<char, 256> buffer;
std::string result;
FILE* pipe = popen("sw_vers -productVersion 2>&1", "r");
if (!pipe) return "Unknown";
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
result += buffer.data();
}
pclose(pipe);
// 去掉末尾换行
if (!result.empty() && result.back() == '
') result.pop_back();
return result;
}
-
sw_vers -productName可得“macOS”,-productVersion得“14.5”,-buildVersion得“23F79” - 不能只靠
sysctl查kern.version,它显示编译信息(含XNU版本),与用户看到的版本无关 - 若需完整名称(如“macOS Sonoma 14.5”),需硬编码映射表:14.x → Sonoma,13.x → Ventura
跨平台封装要注意ABI和错误处理边界
不同系统返回的信息粒度差异极大:Windows给内核版+注册表名,Linux给发行版全名,macOS只给数字版号。强行统一成单一字符串容易失真。
- 避免在头文件里写
#ifdef _WIN32混杂逻辑,用编译期多态或运行时分发更清晰 - 所有外部调用(注册表、文件读取、
popen)都可能失败,必须检查返回值,不能假设路径或键存在 - 字符串编码:Windows注册表默认UTF-16,Linux文件是UTF-8,macOS命令输出也是UTF-8——跨平台时
std::stringvsstd::wstring选择要谨慎 - 真正需要“详细版本名称”的场景(如日志、诊断报告),建议分字段返回:
os_name、os_version、os_codename(可空),而不是拼成一个字符串
系统版本字符串从来不是原子值,它由多个异构数据源拼凑而成,任何试图一步到位的封装都会在某个平台上露馅。

















