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

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

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

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


person perimosocordiae    schedule 26.09.2008    source источник
comment
возможный дубликат компиляции C ++ в Windows и Linux: переключатель ifdef   -  person Cory Klein    schedule 19.09.2013
comment
@ Кори Кляйн: Нет-нет. этот вопрос задавали много лет назад   -  person John_West    schedule 03.01.2016
comment
Речь идет о C, а не о C++   -  person ilgaar    schedule 21.01.2019
comment
@CoryKlein Нет, этот вопрос дублирует этот вопрос.   -  person Akib Azmain    schedule 10.10.2020
comment
@AkibAzmain Ты вернул меня в историю! Вау, что за старый вопрос. Когда я впервые прокомментировал 7 лет назад, мне было уже 5 лет! Интересно, что сравнительный возраст не является окончательным критерием для выбора дубликата, но в данном случае похоже, что другой был отмечен как дубликат много лет назад, так что это спорный вопрос. Хорошего дня!   -  person Cory Klein    schedule 10.10.2020


Ответы (15)


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

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__

Android

__ANDROID__

person Lambda Fairy    schedule 23.11.2011
comment
Данный сайт не включает iOS, поэтому он не может отличить iOS от OS X. - person Gary Makin; 30.04.2014
comment
Mac OS не определяет __unix__. Почему вы включили его в список? - person Victor Sergienko; 19.04.2018
comment
cpp -dM / dev / null предоставит вам список всех предопределенных макросов gcc в вашей версии установленного gcc - person katta; 10.09.2018
comment
Cygwin определяет символы unix и не определяет символы win32, поэтому будьте осторожны. OTOH определяет __CYGWIN__. - person David Given; 24.09.2018
comment
__linux__ то же самое, что __ANDROID__ ?? - person ; 09.03.2020
comment
Почему __linux не соответствует стандарту POSIX? - person Ayxan Haqverdili; 03.05.2020
comment
Ссылка Windows не работает - person Ayxan Haqverdili; 03.05.2020
comment
_AIX для IBM AIX соответственно. - person Mikhail Zakharov; 04.06.2020

показать 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
person qwer    schedule 15.03.2009
comment
Windows и Unices - не единственные операционные системы - person phuclv; 24.02.2019
comment
Это удобно, но учтите, что unix, __unix__, __unix не работают в macOS, где определены только __APPLE__ и __MACH__. - person mklement0; 07.06.2021

На основе https://web.archive.org/web/20191012035921/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system.

#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 и лязгает:

  • Debian 8
  • Окна (MinGW)
  • Windows (Cygwin)
person PADYMKO    schedule 04.02.2017
comment
уважаемый @MD XF, укажите версии ваших Windows, MinGW и Cygwin - person PADYMKO; 08.03.2017
comment
Windows 7 Корпоративная 6.1.7601. Cygwin 2.7.0-1. Я не могу найти версию MinGW, но я ее вчера скачал. - person MD XF; 08.03.2017
comment
Вы, вероятно, должны знать - эта программа является стандартной для C, поэтому она должна работать во всех совместимых системах. - person MD XF; 08.03.2017
comment
дорогой @MD XF, спасибо за эту информацию. Я добавил вас как соавтора поверх этого ответа. - person PADYMKO; 08.03.2017

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

person quinmars    schedule 26.09.2008
comment
есть ли простой способ проверить, определена ли функция? - person hayalci; 27.09.2008
comment
Если вы используете автонастройку, вы можете проверить функции с помощью AC_CHECK_FUNCS (). AC_CHECK_FUNCS (pipe sqrt) будет определять HAVE_PIPE и HAVE_SQRT, если функции доступны. Я не знаю, как обстоят дела с другими строительными инструментами, но я думаю, они тоже в некотором роде поддерживают это. - person quinmars; 27.09.2008
comment
@MDXF Начиная с C ++ 17, существует __has_include. Я не думаю, что он стандартизирован в C, но все основные компиляторы (GCC, Clang, ICC, MSVC) реализуют его как расширение для конкретного производителя, даже в режиме C. - person Alcaro; 04.01.2019

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

Думаю, вы ищете:

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

Предопределенные макросы компилятора gcc можно найти здесь

Думаю, вы ищете:

  • __GNUC__
  • __GNUC_MINOR__
  • __GNUC_PATCHLEVEL__

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

person Martin York    schedule 26.09.2008

Не существует стандартного макроса, установленного в соответствии со стандартом C. Некоторые компиляторы C устанавливают его на некоторых платформах (например, исправленный GCC от Apple устанавливает макрос, указывающий, что он компилируется в системе 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
person Mecki    schedule 27.09.2008

В MinGW проверка _WIN32 define не работает. Вот решение:

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

person anakod    schedule 27.01.2017
comment
Отличная ссылка. --- - person MD XF; 08.03.2017


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

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

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

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

person devio    schedule 26.09.2008


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

См. Также Как получить идентификаторы платформ из ускорения

person phuclv    schedule 25.10.2018

Я не нашел здесь определения Haiku. Чтобы быть полным, определение Haiku-os простое __HAIKU__

person TadejP    schedule 11.10.2018

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

person davenpcj    schedule 26.09.2008
comment
gcc: error: нераспознанный параметр командной строки '--show-define' gcc: фатальная ошибка: компиляция входных файлов не завершена. - person Sebi2020; 24.08.2016

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

#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;
}
person HaseeB Mir    schedule 10.01.2018

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

person abranhe    schedule 12.11.2018