关于C#:如何使用预处理器指令检查OS?

How do I check OS with a preprocessor directive?

我需要我的代码根据编译它的操作系统做不同的事情。 我在寻找这样的东西:

1
2
3
4
5
#ifdef OSisWindows
// do Windows-specific stuff
#else
// do Unix-specific stuff
#endif

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


OS网站的预定义宏具有非常完整的检查列表。以下是其中一些内容,以及指向它们的位置的链接:

视窗

_WIN32    32位和64位
_WIN64   仅限64位

Unix(Linux,* BSD,Mac OS X)

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

unix

__unix

__unix__

Mac OS X.

__APPLE__

__MACH__

两者都是定义的;检查要么应该工作。

Linux的

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

FreeBSD的

__FreeBSD__


显示GCC在Windows上定义:

1
gcc -dM -E - <NUL:

在Linux上:

1
gcc -dM -E - </dev/null

MinGW中的预定义宏:

1
WIN32 _WIN32 __WIN32 __WIN32__ __MINGW32__ WINNT __WINNT __WINNT__ _X86_ i386 __i386

在UNIX上:

1
unix __unix__ __unix


基于nadeausoftware和Lambda Fairy的回答。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#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
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)


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


1
2
3
4
5
6
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

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

https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros

我想你正在寻找:

_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编译器PreDefined MAcros可以在这里找到:

http://gcc.gnu.org/onlinedocs/cpp/Predefined-Macros.html

我想你正在寻找:

__GNUC__
__GNUC_MINOR__
__GNUC_PATCHLEVEL__

为您预先定义的适当编译器做谷歌。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#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/


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

就像hayalci所说的那样,最好在构建过程中以某种方式设置这些宏。在不修改代码的情况下,很容易用大多数编译器定义宏。你可以简单地将-D MACRO传递给GCC,即

1
2
gcc -D Windows
gcc -D UNIX

在你的代码中:

1
2
3
4
5
6
7
#if defined(Windows)
// do some cool Windows stuff
#elif defined(UNIX)
// do some cool Unix stuff
#else
#    error Unsupported operating system
#endif

总结一下,这里有一堆有用的链接。

  • GCC通用预定义宏
  • SourceForge预定义的操作系统
  • MSDN预定义宏
  • 多链接的NaudeaSoftware页面
  • 维基百科!
  • SourceForge的"用于标准,编译器,操作系统和硬件架构的预定义编译器宏概述"。
  • FreeBSD的"差异化操作系统"
  • 各种预定义的宏
  • libportable

使用#define OSsymbol#ifdef OSsymbol
其中OSsymbol是一个#define'符号,用于标识您的目标操作系统。

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

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

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


很抱歉外部参考,但我认为它适合您的问题:

C / C ++提示:如何使用编译器预定义的宏检测操作系统类型


有些编译器会生成#defines,可以帮助你解决这个问题。阅读编译器文档以确定它们是什么。 MSVC定义了一个__WIN32__,GCC有一些你可以用touch foo.h; gcc -dM foo.h看到的


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

安装

1
$ clib install abranhe/os.c

用法

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include"os.h"

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

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


你可以使用预处理器指令作为警告或错误来检查编译时你根本不需要运行这个程序就可以编译它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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;
}

我没有在这里找到Haiku的定义。要完成,Haiku-os定义很简单__HAIKU__


您可以使用Boost.Predef,其中包含用于目标平台(包括操作系统)的各种预定义宏。 是的boost通常被认为是一个C ++库,但是这个也是一个与C一起使用的预处理器头

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.

例如

1
2
3
4
5
6
7
8
#include <boost/predef.h>

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