How do I check OS with a preprocessor directive? - c

I need my code to do different things based on the operating system on which it gets compiled. I'm looking for something like this:
#ifdef OSisWindows
// do Windows-specific stuff
#else
// do Unix-specific stuff
#endif
Is there a way to do this? Is there a better way to do the same thing?

The Predefined Macros for OS site has a very complete list of checks. Here are a few of them, with links to where they're found:
Windows
_WIN32   Both 32 bit and 64 bit
_WIN64   64 bit only
__CYGWIN__
Unix (Linux, *BSD, but not Mac OS X)
See this related question on some of the pitfalls of using this check.
unix
__unix
__unix__
Mac OS X
__APPLE__ Also used for classic
__MACH__
Both are defined; checking for either should work.
Linux
__linux__
linux Obsolete (not POSIX compliant)
__linux Obsolete (not POSIX compliant)
FreeBSD
__FreeBSD__
Android
__ANDROID__

show GCC defines on Windows:
gcc -dM -E - <NUL:
on Linux:
gcc -dM -E - </dev/null
Predefined macros in MinGW:
WIN32 _WIN32 __WIN32 __WIN32__ __MINGW32__ WINNT __WINNT __WINNT__ _X86_ i386 __i386
on UNIXes:
unix __unix__ __unix

Based on nadeausoftware and Lambda Fairy's answer.
#include <stdio.h>
/**
* Determination a platform of an operation system
* Fully supported supported only GNU GCC/G++, partially on Clang/LLVM
*/
#if defined(_WIN32)
#define PLATFORM_NAME "windows" // Windows
#elif defined(_WIN64)
#define PLATFORM_NAME "windows" // Windows
#elif defined(__CYGWIN__) && !defined(_WIN32)
#define PLATFORM_NAME "windows" // Windows (Cygwin POSIX under Microsoft Window)
#elif defined(__ANDROID__)
#define PLATFORM_NAME "android" // Android (implies Linux, so it must come first)
#elif defined(__linux__)
#define PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other
#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__)
#include <sys/param.h>
#if defined(BSD)
#define PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD
#endif
#elif defined(__hpux)
#define PLATFORM_NAME "hp-ux" // HP-UX
#elif defined(_AIX)
#define PLATFORM_NAME "aix" // IBM AIX
#elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin)
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
#define PLATFORM_NAME "ios" // Apple iOS
#elif TARGET_OS_IPHONE == 1
#define PLATFORM_NAME "ios" // Apple iOS
#elif TARGET_OS_MAC == 1
#define PLATFORM_NAME "osx" // Apple OSX
#endif
#elif defined(__sun) && defined(__SVR4)
#define PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana
#else
#define PLATFORM_NAME NULL
#endif
// Return a name of platform, if determined, otherwise - an empty string
const char *get_platform_name() {
return (PLATFORM_NAME == NULL) ? "" : PLATFORM_NAME;
}
int main(int argc, char *argv[]) {
puts(get_platform_name());
return 0;
}
Tested with GCC and clang on:
Debian 8
Windows (MinGW)
Windows (Cygwin)

Microsoft C/C++ compiler (MSVC) Predefined Macros can be found here
I think you are looking for:
_WIN32 - Defined as 1 when the compilation target is 32-bit ARM, 64-bit ARM, x86, or x64. Otherwise, undefined
_WIN64 - Defined as 1 when the compilation target is 64-bit ARM or x64. Otherwise, undefined.
gcc compiler PreDefined MAcros can be found here
I think you are looking for:
__GNUC__
__GNUC_MINOR__
__GNUC_PATCHLEVEL__
Do a google for your appropriate compilers pre-defined.

In most cases it is better to check whether a given functionality is present or not. For example: if the function pipe() exists or not.

#ifdef _WIN32
// do something for windows like include <windows.h>
#elif defined __unix__
// do something for unix like include <unistd.h>
#elif defined __APPLE__
// do something for mac
#endif

On MinGW, the _WIN32 define check isn't working. Here's a solution:
#if defined(_WIN32) || defined(__CYGWIN__)
// Windows (x86 or x64)
// ...
#elif defined(__linux__)
// Linux
// ...
#elif defined(__APPLE__) && defined(__MACH__)
// Mac OS
// ...
#elif defined(unix) || defined(__unix__) || defined(__unix)
// Unix like OS
// ...
#else
#error Unknown environment!
#endif
For more information please look: https://sourceforge.net/p/predef/wiki/OperatingSystems/

There is no standard macro that is set according to C standard. Some C compilers will set one on some platforms (e.g. Apple's patched GCC sets a macro to indicate that it is compiling on an Apple system and for the Darwin platform). Your platform and/or your C compiler might set something as well, but there is no general way.
Like hayalci said, it's best to have these macros set in your build process somehow. It is easy to define a macro with most compilers without modifying the code. You can simply pass -D MACRO to GCC, i.e.
gcc -D Windows
gcc -D UNIX
And in your code:
#if defined(Windows)
// do some cool Windows stuff
#elif defined(UNIX)
// do some cool Unix stuff
#else
# error Unsupported operating system
#endif

Sorry for the external reference, but I think it is suited to your question:
C/C++ tip: How to detect the operating system type using compiler predefined macros

You can use Boost.Predef which contains various predefined macros for the target platform including the OS (BOOST_OS_*). Yes boost is often thought as a C++ library, but this one is a preprocessor header that works with C as well!
This library defines a set of compiler, architecture, operating system, library, and other version numbers from the information it can gather of C, C++, Objective C, and Objective C++ predefined macros or those defined in generally available headers. The idea for this library grew out of a proposal to extend the Boost Config library to provide more, and consistent, information than the feature definitions it supports. What follows is an edited version of that brief proposal.
For example
#include <boost/predef.h>
// or just include the necessary header
// #include <boost/predef/os.h>
#if BOOST_OS_WINDOWS
#elif BOOST_OS_ANDROID
#elif BOOST_OS_LINUX
#elif BOOST_OS_BSD
#elif BOOST_OS_AIX
#elif BOOST_OS_HAIKU
...
#endif
The full list can be found in BOOST_OS operating system macros
Demo on Godbolt
See also How to get platform IDs from boost?

Use #define OSsymbol and #ifdef OSsymbol
where OSsymbol is a #define'able symbol identifying your target OS.
Typically you would include a central header file defining the selected OS symbol and use OS-specific include and library directories to compile and build.
You did not specify your development environment, but I'm pretty sure your compiler provides global defines for common platforms and OSes.
See also http://en.wikibooks.org/wiki/C_Programming/Preprocessor

Just to sum it all up, here are a bunch of helpful links.
GCC Common Predefined Macros
SourceForge predefined Operating Systems
MSDN Predefined Macros
The Much-Linked NaudeaSoftware Page
Wikipedia!!!
SourceForge's "Overview of pre-defined compiler macros for standards, compilers, operating systems, and hardware architectures."
FreeBSD's "Differentiating Operating Systems"
All kinds of predefined macros
libportable

I did not find Haiku definition here. To be complete, Haiku-os definition is simple __HAIKU__

Some compilers will generate #defines that can help you with this. Read the compiler documentation to determine what they are. MSVC defines one that's __WIN32__, GCC has some you can see with touch foo.h; gcc -dM foo.h

You can use pre-processor directives as warning or error to check at compile time you don't need to run this program at all just simply compile it .
#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
#error Windows_OS
#elif defined(__linux__)
#error Linux_OS
#elif defined(__APPLE__) && defined(__MACH__)
#error Mach_OS
#elif defined(unix) || defined(__unix__) || defined(__unix)
#error Unix_OS
#else
#error Unknown_OS
#endif
#include <stdio.h>
int main(void)
{
return 0;
}

I wrote an small library to get the operating system you are on, it can be installed using clib (The C package manager), so it is really simple to use it as a dependency for your projects.
Install
$ clib install abranhe/os.c
Usage
#include <stdio.h>
#include "os.h"
int main()
{
printf("%s\n", operating_system());
// macOS
return 0;
}
It returns a string (char*) with the name of the operating system you are using, for further information about this project check it out the documentation on Github.

Related

Determine the operating system variable in a C preprocessor directive

I am posting yet another programming task that I can't solve. Suppose we write OS-specific preprocessor directives like:
#if OS == Linux
/* Linux-specific instructions */
...
#else
#if OS == Darwin
/* Mac OSX-specific instructions */
...
#else
/* Program code for other OS */
...
#endif
#endif
We are not allowed to use #define OS Linux; instead the variable OS should be set with the compiler (or alternatively in a makefile). There should also be a shell-command which can automatically define OS. How can we set OS-Variable using the compiler or the shell?
Kind regards
The C preprocessor can only compare integer values, not strings or any other type. When you write #if OS == Linux, the preprocessor first expands the macros OS and Linux (and any macros in their expansions, etc.). Once it's finished expanding, it treats the whole line (after #if itself) as a preprocessor expression and evaluates it. Like with the C language proper, the directive is true if the value is nonzero, and boolean operators like == evaluate to 1 if true and 0 if false.
So for #if OS == Linux to work, you have to choose a numerical value for Linux (and a different value for all the other operating systems). Then you need to assign OS to the same value. For example, if suppose you have a header operating_systems.h containing
#define Linux 1
#define Darwin 2
#define Windows 3
then you can use #define OS 1 or #define OS (7 - 6) or #define OS Linux or any equivalent method to make #if OS == Linux true.
Note that if Linux and Darwin are undefined and you define OS to either Linux or Darwin, then both OS == Linux and OS == Darwin will be true, because undefined macro names in preprocessor expressions have the value 0. This kind of “enum-like” conditional is error-prone since undefined values (or values from the wrong “enum” series) will not be caught, so it isn't a good idea.
This is quite an unusual way to select between operating systems. Usually, system selection is based on whether certain macros are defined or not. For example, all compilers for Linux should define __linux__, all compilers for macOS should define __APPLE__, etc. To find out what macros are predefined, consult the documentation of your compiler or operating system (including applicable standards, e.g. POSIX), or ask your compiler (e.g. cpp -dM /dev/null).
So typical OS-specific code looks like this:
#if defined(__APPLE__)
// macOS or iOS code
#elif defined(__unix__)
// code for Unix-like systems
# if defined(__linux__)
// additional code for Linux
# endif
#elif defined(_WIN32) || defined(_WIN64)
// code for Windows
#else
#error "Unknown operating system"
#endif
If you need to select additional information during the build which can't be determined by the compiler alone, most compilers have a way to predefine additional macros. On Unix-like compilers (including GCC, Clang and many others), you do this by passing -DMACRO_NAME or -DMACRO_NAME=expansion on the command line. For example, if you compile with
gcc -DPROTOCOL_VERSION=3
then you can write code like this:
#if PROTOCOL_VERSION == 1
#error "Protocol version 1 is no longer supported."
#elif PROTOCOL_VERSION == 2
// code for version 2
#elif PROTOCOL_VERSION == 3
// code for version 3
#else
#error "An unsupported protocol version was requrested"
#endif
(This example assumes your code is only capable of supporting a single protocol version.)

What is the compiler-defined macro for WASM?

What is the macro that clang and/or gcc would define when compiling for a WASM backend?
To clarify, one can write platform-specific code using macros the compiler defines like so:
#if _WIN32
// Windows-specific code
#elif __linux__
// Linux-specific code
#elif __APPLE__
// macOS-specific code
#else
#error Unsupported platform
#endif
I would like to do the same thing specifying WebAssembly as one of the potential backends.
As per #Jonathan Leffler's comment, there does not appear to be a standard macro that is defined across compilers.
My current solution for working with different compilers is to create a separate build job for WASM that defines a macro. For gcc and clang, it passes the flag -D__WASM__ to define a __WASM__ macro.
In my setup, I just change an environment variable and my build script selects the appropriate build flags.

Using macros WIN32 or _MSC_VER cross-platform

I am compiling under Linux (GCC 4.4.2) and Windows VS C++ Express Edition 2008
I am currently compiling under Windows XP Pro 32 bit, and have added this to my source code.
#if defined( WIN32 )
/* Do windows stuff here */
#endif
However, the code in the if statement is disabled (grayed out). However if I do the following:
#if defined( _MSC_VER )
/* Do windows stuff here */
#endif
The if statement code is enabled.
I am just wondering, what should I be using. I have seen many programmers use WIN32. However, doesn't seem to work for me. Should I be using _MSC_VER instead?
Many thanks for any advice,
There is no WIN32. If you've seen it being used elsewhere, it's either wrong or the code is explicitly defining that macro itself somewhere.
You want _WIN32. See https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros for a list of predefined macros in Microsoft's compiler.
This worked for me!
#if defined (_WIN32)
#define PLATFORM "Windows"
#elif defined (__linux)
#define PLATFORM "Linux"
#endif
#include <iostream>
using namespace std;
int main()
{
cout << PLATFORM << "System" << endl;
return 0;
}
Use _WIN32 instead. The IntelliSense parser in VS2008 is troublesome, this might not necessarily solve your problem. It got a complete rewrite in VS2010.

Is it possible to check whether you are building for 64-bit with Microsoft C Compiler?

Is there a simple preprocessor macro that is defined for a 64-bit build? I thought _WIN64 might have been it, but even when I build a 32-bit target, the parts enclosed in a #ifdef _WIN64 ... #endif are compiled in, and this is causing problems. It's Friday and I can't think straight, but I'm sure I'm overlooking something very simple here. Maybe even something involving sizeof.
I have always used _WIN64 to check if it is a 64 bit build.
N.B. _WIN32 is also always (automatically) defined by MSVC in 64 bit builds, so check for _WIN64 before you check for _WIN32:
#if defined( _WIN64 )
// Windows 64 bit code here
#elif defined( _WIN32 )
// Windows 32 bit code here
#else
// Non-Windows code here
#endif
It sounds like your problem might be related to a header or project setting improperly defining _WIN64 - that should be left to the compiler.
There's a subtle difference between WIN64 and _WIN64 (at least for the Microsoft compilers - other compilers should follow suit, but not all do):
_WIN64 is defined by the compiler when it's building a program for a Windows 64-bit platform. Note that this name is in the compiler implementor's namespace (leading underscore followed by a capital letter)
WIN64 is defined by the Windows Platform SDK (or whatever they're calling it this year) when targeting a 64-bit platform.
So if you're only including standard headers and don't take other measures to define it, WIN64 will not be defined.
There's a similar story for _WIN32 and WIN32 - but checking other compilers: GCC 3.4.5 does define WIN32 even if only standard headers are used. As does Digital Mars.
Microsoft's compilers and Comeau do not.
Another bit of (hopefully) well known trivia is that _WIN32 and WIN32 are set when targeting 64-bit Windows platforms. Too much stuff would have broken otherwise.
The Visual C++ compiler defines the following macros:
_M_IX86 - x86 platform
_M_IA64 - ia64 platform
_M_X64 - x64 platform
Check your project's build properties, particularly the preprocessor section. Are you defining _WIN64 somewhere in WIN32 builds? The sizeof thing probably won't work since you cannot use in a #if test.

What C preprocessor conditional should I use for OS X specific code?

What C preprocessor conditional should I use for OS X specific code? I need to include a specific library if I am compiling for OS X or a different header if I am compiling for Linux.
I know there is __APPLE__ but I don't know if that is a current conditional for OS X 10.x.
This list of operating system macros says the presence of both __APPLE__ and __MACH__ indicate OSX.
Also confirmed at line 18 of part of the source for fdisk.
__APPLE__ will tell you you're compiling on an Apple platform. Unless you need to support MacOS versions before OS X, that should be good enough. Alternately, you could use __APPLE__ and __MACH__ to make sure you're compiling on OS X.
If I remember correctly, it's __APPLE__ :)
This code example may help you -
if defined(__APPLE__)
#include "TargetConditionals.h"
if (!defined(TARGET_OS_IPHONE) && !defined(TARGET_IPHONE_SIMULATOR))
{
//write your OSX specific code here
}
old style raw:
#ifdef WIN32
// windows.
#elif __APPLE__
// osx and ios.
#endif
This page contains a list of all OS predefined macros.
For mac OSX both the __APPLE__ && __MACH__ need to be defined.

Resources