如何使用预处理指令检查OS?


194

我需要我的代码根据要在其上进行编译的操作系统来执行不同的操作。我正在寻找这样的东西:

#ifdef OSisWindows
// do Windows-specific stuff
#else
// do Unix-specific stuff
#endif

有没有办法做到这一点?有没有更好的方法来做同样的事情?



7
@Cory Klein:不。这个问题在几年前就已经问过了
John_West

这大概C不是C++
ilgaar

Answers:


288

用于操作系统预定义宏”站点具有非常完整的检查列表。以下是其中一些内容,以及指向这些内容的链接:

视窗

_WIN32
_WIN64   仅   32位和64位64位

Unix(Linux,* BSD,Mac OS X)

有关使用此检查的一些陷阱,请参阅此相关问题

unix
__unix
__unix__

Mac OS X

__APPLE__
__MACH__

两者都被定义;检查任何一个都可以。

的Linux

__linux__
linux 已过时(不符合POSIX)
__linux已过时(不符合POSIX)

FreeBSD

__FreeBSD__

安卓系统

__ANDROID__


1
本网站给出不包括iOS的,所以它不能够iOS和OS X之间进行区分
加里·麦金

2
Mac OS没有定义__unix__。为什么将其包括在列表中?
Victor Sergienko '18

1
cpp -dM / dev / null将为您提供已安装gcc版本上所有gcc预定义宏的列表
katta

1
Cygwin定义unix符号而未定义符号win32,因此请小心。OTOH确实定义了__CYGWIN__
大卫·

__linux__相同__ANDROID__??
没有人

72

在Windows上显示GCC定义:

gcc -dM -E - <NUL:

在Linux上:

gcc -dM -E - </dev/null

MinGW中的预定义宏:

WIN32 _WIN32 __WIN32 __WIN32__ __MINGW32__ WINNT __WINNT __WINNT__ _X86_ i386 __i386

在UNIX上:

unix __unix__ __unix

1
Windows和
Unices

34

基于nadeausoftwareLambda Fairy的答案

#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;
}

经过GCC和clang测试:

  • Debian 8
  • Windows(MinGW)
  • Windows(Cygwin)

亲爱的@MD XF,请指出Windows,MinGW和Cygwin的版本
PADYMKO

Windows 7企业版6.1.7601。Cygwin 2.7.0-1。我找不到MinGW版本,但昨天下载了它。
MD XF

但是,您可能应该使您知道-该程序是标准C,因此它应可在所有兼容的系统上运行。
MD XF

亲爱的@MD XF,感谢您提供此信息。我将您添加为该答案的贡献者。
PADYMKO

10

在大多数情况下,最好检查给定的功能是否存在。例如:该函数是否pipe()存在。


3
有没有一种简单的方法来检查是否定义了函数?
hayalci

1
如果使用自动配置,则可以使用AC_CHECK_FUNCS()检查功能。如果功能可用,AC_CHECK_FUNCS(pipe sqrt)将定义HAVE_PIPE和HAVE_SQRT。我不知道其他构建工具的情况如何,但是我想他们也以某种方式支持这一点。
quinmars

@MDXF从C ++ 17开始,有__has_include。我认为它尚未在C中标准化,但是所有主要的编译器(GCC,Clang,ICC,MSVC)都将其实现为特定于供应商的扩展,即使在C模式下也是如此。
Alcaro

7
#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

5

可以在此处找到Microsoft C / C ++编译器(MSVC)预定义宏

我认为您正在寻找:

  • _WIN32-当编译目标是32位ARM,64位ARM,x86或x64时,定义为1。否则,未定义
  • _WIN64-当编译目标是64位ARM或x64时,定义为1。否则,未定义。

gcc编译器预定义的宏可以在这里找到

我认为您正在寻找:

  • __GNUC__
  • __GNUC_MINOR__
  • __GNUC_PATCHLEVEL__

为您预定义的适当编译器创建一个google。


4

没有根据C标准设置的标准宏。一些C编译器会在某些平台上设置一个(例如,Apple修补的GCC设置了一个宏,以指示它正在Apple系统上进行编译并用于Darwin平台)。您的平台和/或C编译器可能也会进行设置,但是没有通用的方法。

就像hayalci所说,最好以某种方式在构建过程中设置这些宏。使用大多数编译器定义宏很容易,而无需修改代码。您可以简单地传递-D MACRO给GCC,即

gcc -D Windows
gcc -D UNIX

在您的代码中:

#if defined(Windows)
// do some cool Windows stuff
#elif defined(UNIX)
// do some cool Unix stuff
#else
#    error Unsupported operating system
#endif

4

在MinGW上,_WIN32定义检查不起作用。这是一个解决方案:

#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

有关更多信息,请查看:https : //sourceforge.net/p/predef/wiki/OperatingSystems/


3
很棒的链接。---
MD XF

2

使用#define OSsymbol#ifdef OSsymbol 其中OSsymbol是#define标识目标OS 的'able符号。

通常,您将包括定义所选OS符号的中央头文件,并使用特定于OS的包含目录和库目录进行编译和构建。

您没有指定开发环境,但是我很确定您的编译器为通用平台和操作系统提供了全局定义。

另请参见http://en.wikibooks.org/wiki/C_Programming/Preprocessor




2

您可以使用Boost.Predef其中包含目标平台(包括OS(BOOST_OS_*))的各种预定义宏。是的,boost通常被认为是C ++库,但这是一个预处理程序标头,它也可以与C一起使用!

该库从其可以收集的C,C ++,Objective C和Objective C ++预定义宏或在通常可用的标头中定义的信息中定义了一组编译器,体系结构,操作系统,库和其他版本号。该库的想法源自提议扩展Boost Config库以提供比其支持的功能定义更多,更一致的信息。接下来是该简要建议的编辑版本。

例如

#include <boost/predef.h>

#if defined(BOOST_OS_WINDOWS)
#elif defined(BOOST_OS_ANDROID)
#elif defined(BOOST_OS_LINUX)
#elif defined(BOOST_OS_BSD)
#elif defined(BOOST_OS_AIX)
#elif defined(BOOST_OS_HAIKU)
...
#endif

完整列表可以在操作系统宏中找到BOOST_OS


1

我在这里找不到Haiku定义。为了完整起见,Haiku-os的定义很简单__HAIKU__


0

一些编译器会生成#defines来帮助您。阅读编译器文档以确定它们是什么。MSVC定义了一个__WIN32__GCC有一些您可以看到的touch foo.h; gcc -dM foo.h


1
gcc:错误:无法识别的命令行选项'--show-defines'gcc:致命错误:没有输入文件编译终止。
Sebi2020 '16

0

您可以将预处理器指令用作警告或错误,以在编译时进行检查,而无需完全运行该程序,只需编译即可。

#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;
}

0

我编写了一个小库来获取您所使用的操作系统,可以使用clib(C包管理器)安装该库,因此将其用作项目的依赖项确实非常简单。

安装

$ clib install abranhe/os.c

用法

#include <stdio.h>
#include "os.h"

int main()
{
    printf("%s\n", operating_system());
    // macOS
    return 0;
}

它返回一个char*带有您正在使用的操作系统名称的字符串(),有关此项目的更多信息,请查看Github上的文档

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.