在 C、C++ 中检测 Windows 或 Linux [重复]
Posted
技术标签:
【中文标题】在 C、C++ 中检测 Windows 或 Linux [重复]【英文标题】:Detect Windows or Linux in C, C++ [duplicate] 【发布时间】:2012-01-29 18:48:56 【问题描述】:我正在编写一个跨平台程序。我希望这个程序能够在 Windows 和 Linux 下运行,所以我为这两个平台提供了两个不同的代码段。如果操作系统是 Windows,我希望运行第一个代码段;如果是 Linux,那么我希望运行第二个代码段。
所以我编写了以下代码,但是在 Windows 和 Linux 上构建时都会出错。我该怎么解决?
#ifdef __unix__ /* __unix__ is usually defined by compilers targeting Unix systems */
#define OS_Windows 0
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#elif defined(_WIN32) || defined(WIN32) /* _Win32 is usually defined by compilers targeting 32 or 64 bit Windows systems */
#define OS_Windows 1
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define DIV 1048576
#define WIDTH 7
#endif
int main(int argc, char *argv[])
if(OS_Windows)
MEMORYSTATUSEX statex;
statex.dwLength = sizeof (statex);
GlobalMemoryStatusEx (&statex);
_tprintf (TEXT("There is %*ld %% of memory in use.\n"),
WIDTH, statex.dwMemoryLoad);
else if(!OS_Windows) // if OS is unix
char cmd[30];
int flag = 0;
FILE *fp;
char line[130];
int memTotal, memFree, memUsed;
flag=0;
memcpy (cmd,"\0",30);
sprintf(cmd,"free -t -m|grep Total");
fp = popen(cmd, "r");
while ( fgets( line, sizeof line, fp))
flag++;
sscanf(line,"%*s %d %d %d",&TotalMem, &TotalUsed, &TotalFree);
pclose(fp);
if(flag)
printf("TotalMem:%d -- TotalUsed:%d -- TotalFree:%d\n",TotalMem,TotalUsed,TotalFree);
else
printf("not found\n");
return 0;
【问题讨论】:
什么样的错误? 发生这种情况是因为编译器正在寻找MEMORYSTATUSEX
,因为if(OS_Windows)
检查不是预处理器检查,它发生在运行时,因此必须编译if
下的所有内容。
@RRR 请记住检查最能解决您的问题的答案旁边的勾号,这就是我们在 SO 上将问题标记为已解决的方式。也请与您的其他问题一起这样做:-)
存在跨平台的 C++ 库,例如 Qt。使用它的 QtCore 模块,您可以在 Linux、MacOSX、Windows 之间可移植地编写非图形应用程序。
@RRR 我保证memcpy(cmd, "\0", 30)
不会做你所期望的。使用memset(cmd, '\0', 30)
【参考方案1】:
一般是这样的(或多或少):
#ifdef _WIN32
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define DIV 1048576
#define WIDTH 7
#endif
#ifdef linux
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#endif
int main(int argc, char *argv[])
#ifdef _WIN32
MEMORYSTATUSEX statex;
statex.dwLength = sizeof (statex);
GlobalMemoryStatusEx (&statex);
_tprintf (TEXT("There is %*ld %% of memory in use.\n"),
WIDTH, statex.dwMemoryLoad);
#endif
#ifdef linux
char cmd[30];
int flag = 0;
FILE *fp;
char line[130];
int TotalMem, TotalFree, TotalUsed;
flag=0;
memcpy (cmd,"\0",30);
sprintf(cmd,"free -t -m|grep Total");
fp = popen(cmd, "r");
while ( fgets( line, sizeof line, fp))
flag++;
sscanf(line,"%*s %d %d %d",&TotalMem, &TotalUsed, &TotalFree);
pclose(fp);
if(flag)
printf("TotalMem:%d -- TotalUsed:%d -- TotalFree:%d\n",TotalMem,TotalUsed,TotalFree);
else
printf("not found\n");
#endif
return 0;
这样,在linux平台上只会编译linux的代码,在windows平台上只会编译windows代码。
【讨论】:
thankzzz.... 你是救命稻草。 @Cicada 编译此代码更改 int memTotal, memFree, memUsed; to int TotalMem, TotalFree, TotalUsed;【参考方案2】:您应该在代码中使用相同的#ifdef
而不是if(OS_Windows)
逻辑:
#ifdef __unix__
...
#elif defined(_WIN32) || defined(WIN32)
#define OS_Windows
#endif
int main(int argc, char *argv[])
#ifdef OS_Windows
/* Windows code */
#else
/* GNU/Linux code */
#endif
【讨论】:
【参考方案3】:我在这里看到了很多不同的解决方案,这让我感到不舒服......如果它们在 Linux 上工作但不能在 Windows 上工作,或者在 Windows 但不能在 Linux 上工作怎么办?如果它们只适用于某些编译器怎么办?等等。
所以我找到了我喜欢的这个链接:https://web.archive.org/web/20191012035921/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
看起来这些是最好的(使用#ifdef、#endif 等):
_WIN32
适用于 Windows 32 位
_WIN64
适用于 Windows 64 位
__unix__
用于 Unix
【讨论】:
链接已失效...考虑提供替代方案吗? @xmoex 这是最近的发展。我将使用存档链接更新我的答案。 @xmoex 要点是它列出了这个或那个或其他操作系统以及这个或那个或其他编译器使用的几十个不同的标志,而上面的这 3 个似乎是最好的用于确定 Windows 与 Linux 的重叠。奖励:对于 Apple/Mac,__APPLE__
和 __MACH__
(不是错字)似乎都可以通用。【参考方案4】:
您将变量(存在于运行时)与预处理器符号(仅存在于编译期间)混淆了。
在你做了#define OS_Windows 1
之类的事情之后,你不能使用符号OS_Windows作为变量并将它放在if()
s中......我的意思是,你可以,但它会在编译过程中扩展为@987654323 @。
对于跨平台项目,您必须使用#if
或#ifdef
以确保编译器为给定的操作系统选择正确的代码部分并且只编译那个。
类似:
void openWindow()
#if OS_Windows
// windows-specific code goes here
#else
// linux-specific code
#endif
【讨论】:
>> "它将在编译期间扩展为if (1)
" 是,如果 OS_Windows
定义为 0,则扩展为 if (0)
。main问题 如果我们在编译时已经知道我们需要哪个分支,为什么要将此分支推迟到运行时。所以通过#if
-constructions,我们可以避免额外的运行时间和额外的代码【参考方案5】:
你的基本策略存在严重缺陷。
通过在 main 函数中使用 if,您可以选择在 RUNTIME 运行的代码块。 因此,即使为 unix 编译,编译器仍然必须为 windows 构建代码(因为没有包含头文件,所以它无法执行此操作),反之亦然。
您需要 #if ,它将在编译时进行评估,并且不会尝试编译不相关的代码。
所以本质上你需要理解 if 在运行时将你的定义评估为表达式,而 #if 在编译时评估预定义常量的值。
【讨论】:
任何值得称道的优化编译器都会删除if(0)
块。
@Dave 不幸的是,这并没有真正的帮助,因为编译器无法优化任何它不会开始编译的东西
我的意思是问题不在于无关符号;这是不存在的。
@Dave 同样,当-O0
时,任何有价值的编译器也将不删除if(0)
。以上是关于在 C、C++ 中检测 Windows 或 Linux [重复]的主要内容,如果未能解决你的问题,请参考以下文章
使用 IOCP - C++ - Windows 检测子进程的退出/失败
在 Windows 中编程 C 或 C++ 时如何操作 GUID?
堆栈缓冲区溢出(Windows,C++):如何检测罪魁祸首?