Як перевірити ОС за допомогою директиви препроцесора?


195

Мені потрібен мій код, щоб робити різні речі на основі операційної системи, на якій він збирається. Я шукаю щось подібне:

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

Чи є спосіб це зробити? Чи є кращий спосіб зробити те ж саме?



8
@Cory Klein: Ні-ні. це питання було задано роками раніше
John_West

CC++
Мова

Відповіді:


290

На веб-сайті заздалегідь визначених макросів є дуже повний перелік перевірок. Ось декілька з них із посиланнями на те, де вони знайдені:

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__


1
Цей веб-сайт не включає iOS, тому він не може розрізнити iOS від OS X.
Gary Makin

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

на UNIXes:

unix __unix__ __unix

1
Windows та Unices - не єдині ОС
phuclv

35

Грунтуючись на nadeausoftware та відповіді Феї Ламбда .

#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
  • Windows (MinGW)
  • Windows (Cygwin)

дорогий @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, дякую за цю інформацію. Я додав вас як дописувач поверх цієї відповіді.
ПАДИМКО

10

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


3
чи є простий спосіб перевірити, чи визначена функція?
hayalci

1
Якщо ви використовуєте autoconfig, ви можете перевірити наявність функцій за допомогою AC_CHECK_FUNCS (). AC_CHECK_FUNCS (pipe sqrt) визначатиме HAVE_PIPE та HAVE_SQRT, якщо функції доступні. Я не знаю, як це з іншими будівельними інструментами, але я думаю, що вони також певним чином підтримують це.
квінмар

@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- визначається як 1, коли метою компіляції є 32-розрядна ARM, 64-розрядна ARM, x86 або x64. В іншому випадку не визначено
  • _WIN64- визначається як 1, коли ціль компіляції становить 64-бітний ARM або x64. В іншому випадку не визначено.

gc-компілятор PreDefined MAcros можна знайти тут

Я думаю, ти шукаєш:

  • __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"здатним символом, що ідентифікує вашу цільову ОС.

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

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

Дивіться також http://en.wikibooks.org/wiki/C_Programming/Preprocessor


2

2

Вибачте за зовнішню посилання, але я думаю, що вона підходить до вашого питання:

Порада C / C ++: Як виявити тип операційної системи за допомогою макросів, визначених компілятором


1
Цей мета-пост видалено Смішно, що мета-пост, який запитує про публікації, видалені з міркувань модерації, був видалений з міркувань помірності.
MD XF

:) Так. Абсолютно божевільний
bruziuz

2

Ви можете використовувати Boost.Predefякий містить різні заздалегідь визначені макроси для цільової платформи, включаючи ОС ( BOOST_OS_*). Так, прискорення часто вважається бібліотекою 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__


0

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


1
gcc: помилка: нерозпізнана опція командного рядка '--show-defini' '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;
}

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 .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.