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

195

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

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

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

perimosocordiae
источник
1
Возможный дубликат компиляции C ++ в Windows и Linux: переключатель ifdef
Кори Кляйн,
8
@ Кори Кляйн: Нет-нет. этот вопрос задавался задолго до этого
John_West
Речь идет Cне оC++
Ильгаар

Ответы:

290

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

Windows

_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

__ANDROID__

Лямбда Фея
источник
1
Данный сайт не включает iOS, поэтому он не может различить iOS и OS X.
Гэри Макин
2
Mac OS не определяет __unix__. Зачем вам включать его в список?
Виктор Сергиенко
1
cpp -dM / dev / null предоставит вам список всех предопределенных макросов gcc в вашей версии установленного gcc
katta
1
Cygwin определяет unixсимволы и не определяет win32их, поэтому будьте осторожны. OTOH это определяет __CYGWIN__.
Дэвид Дан
такое __linux__же как __ANDROID__??
никто не
72

show 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
Qwer
источник
1
Windows и Unices не единственные ОС
phuclv
35

На основании 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
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)
PADYMKO
источник
дорогой @MD XF, пожалуйста, укажите версии ваших Windows, MinGW и Cygwin
PADYMKO
Windows 7 Enterprise 6.1.7601. Cygwin 2.7.0-1. Я не могу найти версию MinGW, но я скачал ее вчера.
MD XF
Вы, вероятно, должны быть осведомлены, хотя - эта программа является стандартной C, поэтому она должна работать на всех совместимых системах.
MD XF
Уважаемый @MD XF, спасибо за эту информацию. Я добавил вас как автора этого ответа.
PADYMKO
10

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

quinmars
источник
3
Есть ли простой способ проверить, определена ли функция?
Хаялчи
1
Если вы используете autoconfig, вы можете проверить наличие функций с помощью AC_CHECK_FUNCS (). AC_CHECK_FUNCS (труба sqrt) будет определять HAVE_PIPE и HAVE_SQRT, если функции доступны. Я не знаю, как обстоят дела с другими строительными инструментами, но я думаю, что они также поддерживают это в некотором роде.
Quinmars
@MDXF Начиная с C ++ 17, есть __has_include. Я не думаю, что он еще стандартизирован в C, но все основные компиляторы (GCC, Clang, ICC, MSVC) реализуют его как расширение для конкретного поставщика, даже в режиме C.
Алькаро
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- Определяется как 1, когда целью компиляции является 32-разрядная ARM, 64-разрядная ARM, x86 или x64. В противном случае не определено
  • _WIN64- Определяется как 1, когда целью компиляции является 64-битная ARM или x64. В противном случае не определено.

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

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

  • __GNUC__
  • __GNUC_MINOR__
  • __GNUC_PATCHLEVEL__

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

Мартин Йорк
источник
4

Не существует стандартного макроса, который устанавливается в соответствии со стандартом C. Некоторые компиляторы C устанавливают один на некоторых платформах (например, исправленный GCC от Apple устанавливает макрос для указания того, что он компилируется в системе Apple и для платформы Darwin). Ваша платформа и / или ваш компилятор C могут также что-то устанавливать, но общего пути нет.

Как сказал Хаялчи, лучше всего эти макросы установить в процессе сборки. С большинством компиляторов легко определить макрос без изменения кода. Вы можете просто перейти -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
Mecki
источник
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/

anakod
источник
3
Отличная ссылка. ---
MD XF
2

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

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

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

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

devio
источник
2

Чтобы подвести итог, вот несколько полезных ссылок.

MD XF
источник
2

Извините за внешнюю ссылку, но я думаю, что она подходит для вашего вопроса:

Совет C / C ++: Как определить тип операционной системы, используя предопределенные макросы компилятора

bruziuz
источник
1
Этот мета-пост был удален. Забавно, что мета-пост, спрашивающий о постах, удаленных по причинам модерации, был удален по причинам модерации.
MD XF
:) Да. Абсолютно сумасшедший
bruziuz
2

Вы можете использовать, 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макросах операционной системы.

phuclv
источник
1

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

TadejP
источник
0

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

davenpcj
источник
1
gcc: error: нераспознанная опция командной строки '--show-define' gcc: фатальная ошибка: компиляция входных файлов не прекращена.
Sebi2020
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;
}
HaSeeB MiR
источник
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 .

Авраам Эрнандес
источник