Detect Windows or Linux in C, C++
C++CWindowsLinuxC++ Problem Overview
I am writing a cross platform program. I want this one program to run under both Windows and Linux, so I have two different code segments for the two platforms. If the OS is Windows, I want the first code segment to run; if it's Linux, then I want the second code segment to run.
So I wrote the following code, but it gets an error while building both on Windows and on Linux. What should I do to solve it?
#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;
}
C++ Solutions
Solution 1 - C++
It's generally done like this (more or less):
#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;
}
This way, only code for linux will be compiled while on a linux platform, and only windows code will be compiled on a windows platform.
Solution 2 - C++
You should use the same #ifdef
instead of if(OS_Windows)
logic in your code:
#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
}
Solution 3 - C++
I see a lot of varying solutions here, which makes me uncomfortable... What if they work on Linux but not Windows or on Windows but not Linux? What if they only work on some compilers? Etc.
So I found this link, which I like: https://web.archive.org/web/20191012035921/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
It looks like these are best (using #ifdef, #endif, etc.):
_WIN32
for Windows 32 bit OR 64 bit_WIN64
for Windows 64 bit only__unix__
for Unix
Solution 4 - C++
You are confusing variables (which exist in run-time) with preprocessor symbols (which only exist during compilation).
After you do something like #define OS_Windows 1
, you can't use the symbol OS_Windows as a variable and put it inside if()
s... I mean, you can, but it will be expanded during compilation to if (1)
.
For a cross-platform project, you have to use #if
or #ifdef
to make sure that the compiler chooses a correct part of code for a given OS and compiles only that.
Something like:
void openWindow() {
#if OS_Windows
// windows-specific code goes here
#else
// linux-specific code
#endif
}
Solution 5 - C++
Your basic strategy is deeply flawed.
By using the if in the main function you are selecting which chunk of code to run at RUNTIME. Thus even if compiling for unix the compiler still has to build the code for windows (which it is failing to do because the header files are not included) and visa versa.
You instead required #if which will be evaluated at compile time and will not attempt to compile irrelevant code.
So in essence you need to understand that if evaluates your define as an expression at runtime whereas #if evaluates the value of the predefined constant at compile time.