Как проверить ОС с помощью директивы препроцессора?

Мне нужен мой код, чтобы делать разные вещи на основе операционной системы, на которой он компилируется. Я ищу что-то вроде этого:

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

Есть ли способ сделать это? Есть ли лучший способ сделать то же самое?

Ответ 1

Предустановленные макросы для сайта ОС имеют очень полный список проверок. Вот некоторые из них, со ссылками на которые они найдены:

Windows

_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__

Ответ 2

Существуют предопределенные макросы, которые используются большинством компиляторов, вы можете найти список здесь.

В противном случае вам придется настроить систему сборки так, чтобы макрос, такой как OS_WINDOWS/OS_UNIX, определялся во время компиляции, тогда вам нужно будет проверить его в коде с помощью ifdef.

#ifdef OS_WINDOWS
   // define something for Windows
#else
   // define it for a Unix machine
#endif

Ответ 3

показывает, что GCC определяет в Windows:

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

Ответ 4

На основе nadeausoftware и Lambda 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
char *
get_platform_name() {
    return (PLATFORM_NAME == NULL) ? "" : PLATFORM_NAME;
}

int main(int argc, char *argv[]) {
    puts(get_platform_name());
    return 0;
}

Протестировано с помощью GCC и звонит:

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

Ответ 5

В большинстве случаев лучше проверить наличие данной функции или нет. Например: если существует функция pipe() или нет.

Ответ 6

#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

Ответ 7

Предопределенные макросы Microsoft C/C++ (MSVC) можно найти здесь:

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

Я думаю, что вы ищете:

_WIN32 - определяется как 1, когда целью компиляции является 32-разрядная ARM, 64-разрядная ARM, x86 или x64. В противном случае не определено
_WIN64 - определяется как 1, если целью компиляции является 64-битная ARM или x64. В противном случае не определено.

Компилятор gcc PreDefined MAcros можно найти здесь:

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

Я думаю, что вы ищете:

__GNUC__
__GNUC_MINOR__
__GNUC_PATCHLEVEL__

Сделайте гугл для ваших предопределенных компиляторов.

Ответ 8

Вы, вероятно, найдете этот полезный. В нем перечислены различные предопределенные определения, что разные компиляторы устанавливаются на разных платформах.

Ответ 9

Нет стандартного макроса, который устанавливается в соответствии со стандартом 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

Ответ 10

В 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/

Ответ 11

Используйте #define OSsymbol и #ifdef OSsymbol где OSsymbol является #define 'способным символом, идентифицирующим вашу целевую ОС.

Обычно вы должны включать в себя центральный файл заголовка, определяющий выбранный символ ОС, и использовать для включения и экспорта каталоги включений и библиотек, специфичных для ОС, для компиляции и сборки.

Вы не указали свою среду разработки, но я уверен, что ваш компилятор предоставляет глобальные определения для общих платформ и ОС.

См. также http://en.wikibooks.org/wiki/C_Programming/Preprocessor

Ответ 13

Просто подведем итог, вот куча полезных ссылок.

Ответ 14

Некоторые компиляторы будут генерировать #defines, которые могут помочь вам в этом. Прочтите документацию компилятора, чтобы определить, что они собой представляют. MSVC определяет тот, который __WIN32__, GCC есть некоторые, которые вы можете видеть с помощью touch foo.h; gcc -dM foo.h

Ответ 15

Вы можете использовать предпроцессорные директивы в качестве предупреждения или ошибки для проверки во время компиляции, когда вам вообще не нужно запускать эту программу, просто просто скомпилируйте ее.

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

Ответ 16

Здесь я не нашел определения Хайку. Чтобы быть полным, определение Haiku-os просто __HAIKU__

Ответ 17

Вы можете использовать Boost.Predef который содержит различные предопределенные макросы для целевой платформы, включая ОС. Да, 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)
...
#endif

Ответ 18

Я написал небольшую библиотеку, чтобы получить операционную систему, в которой вы работаете, ее можно установить с помощью 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.