Jak sprawdzić system operacyjny za pomocą dyrektywy preprocesora?

195

Potrzebuję mojego kodu do robienia różnych rzeczy w zależności od systemu operacyjnego, na którym został skompilowany. Szukam czegoś takiego:

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

Czy jest na to sposób? Czy istnieje lepszy sposób na zrobienie tego samego?

perimosocordiae
źródło
8
@Cory Klein: Nie, nie. to pytanie zostało zadane lata wcześniej
John_West
Nie chodzi o CtoC++
ilgaar,

Odpowiedzi:

290

Witryna Predefiniowane makra dla systemu operacyjnego ma bardzo kompletną listę kontroli. Oto kilka z nich, wraz z linkami do miejsca ich znalezienia:

Windows

_WIN32
_WIN64   Tylko    32-bitowy i 64-bitowy tylko 64-bitowy

Unix (Linux, * BSD, Mac OS X)

Zobacz to pokrewne pytanie dotyczące niektórych pułapek korzystania z tego czeku.

unix
__unix
__unix__

Mac OS X

__APPLE__
__MACH__

Oba są zdefiniowane; sprawdzanie obu powinno działać.

Linux

__linux__
linux Przestarzałe (niezgodne z POSIX)
__linuxPrzestarzałe (niezgodne z POSIX)

FreeBSD

__FreeBSD__

Android

__ANDROID__

Lambda Fairy
źródło
1
Podana strona nie zawiera iOS, więc nie jest w stanie odróżnić iOS i OS X.
Gary Makin
2
Mac OS nie definiuje __unix__. Dlaczego warto umieścić to na liście?
Victor Sergienko,
1
CPP -DM / dev / null daje listę wszystkich GCC predefiniowane makra od wersji zainstalowanego gcc
katta
1
Cygwin definiuje unixsymbole i nie definiuje win32tych, więc bądź ostrożny. OTOH to określa __CYGWIN__.
David Biorąc pod uwagę
jest __linux__taki sam jak __ANDROID__??
nikt nie
72

pokaż GCC określa w systemie Windows:

gcc -dM -E - <NUL:

w systemie Linux:

gcc -dM -E - </dev/null

Predefiniowane makra w MinGW:

WIN32 _WIN32 __WIN32 __WIN32__ __MINGW32__ WINNT __WINNT __WINNT__ _X86_ i386 __i386

w systemach UNIX:

unix __unix__ __unix
qwer
źródło
1
Windows i Unices to nie jedyne systemy operacyjne
phuclv
35

Na podstawie nadeausoftware i odpowiedzi Lambdy 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;
}

Testowany z GCC i clang na:

  • Debian 8
  • Windows (MinGW)
  • Windows (Cygwin)
PADYMKO
źródło
drogi @MD XF, proszę wskazać wersje systemu Windows, MinGW i Cygwin
PADYMKO
Windows 7 Enterprise 6.1.7601. Cygwin 2.7.0-1. Nie mogę znaleźć wersji MinGW, ale pobrałem ją wczoraj.
MD XF,
Powinieneś być jednak pewny - ten program jest standardem C, więc powinien działać na wszystkich zgodnych systemach.
MD XF,
drogi @MD XF, dziękuję za te informacje. Dodałem cię jako autora na górze tej odpowiedzi.
PADYMKO
10

W większości przypadków lepiej jest sprawdzić, czy dana funkcjonalność jest obecna, czy nie. Na przykład: jeśli funkcja pipe()istnieje, czy nie.

chinmary
źródło
3
czy istnieje prosty sposób sprawdzenia, czy funkcja jest zdefiniowana?
hayalci
1
Jeśli używasz autokonfiguracji, możesz sprawdzić funkcje za pomocą AC_CHECK_FUNCS (). AC_CHECK_FUNCS (potok sqrt) zdefiniuje HAVE_PIPE i HAVE_SQRT, jeśli funkcje są dostępne. Nie wiem, jak to jest z innymi narzędziami budowlanymi, ale wydaje mi się, że w pewien sposób to obsługują.
quinmars
@MDXF Od wersji C ++ 17 istnieje __has_include. Nie sądzę, aby był on jeszcze ustandaryzowany w języku C, ale wszystkie główne kompilatory (GCC, Clang, ICC, MSVC) implementują go jako rozszerzenie specyficzne dla producenta, nawet w trybie 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
Arjun Sreedharan
źródło
5

Wstępnie zdefiniowane makra kompilatora Microsoft C / C ++ (MSVC) można znaleźć tutaj

Myślę, że szukasz:

  • _WIN32- Zdefiniowane jako 1, gdy celem kompilacji jest 32-bitowy ARM, 64-bitowy ARM, x86 lub x64. W przeciwnym razie nieokreślony
  • _WIN64- Zdefiniowane jako 1, gdy celem kompilacji jest 64-bitowy ARM lub x64. W przeciwnym razie nieokreślony.

Kompilator gcc PreDefined MAcros można znaleźć tutaj

Myślę, że szukasz:

  • __GNUC__
  • __GNUC_MINOR__
  • __GNUC_PATCHLEVEL__

Zrób google dla swoich predefiniowanych kompilatorów.

Martin York
źródło
4

Nie ma standardowego makra ustawionego zgodnie ze standardem C. Niektóre kompilatory C ustawiają jeden na niektórych platformach (np. Załatany GCC Apple ustawia makro wskazujące, że kompiluje się na systemie Apple i na platformie Darwin). Twoja platforma i / lub kompilator C również mogą coś ustawić, ale nie ma ogólnego sposobu.

Jak powiedział hayalci, najlepiej jest ustawić te makra w procesie kompilacji. W większości kompilatorów łatwo jest zdefiniować makro bez modyfikowania kodu. Możesz po prostu przejść -D MACROdo GCC, tj

gcc -D Windows
gcc -D UNIX

I w twoim kodzie:

#if defined(Windows)
// do some cool Windows stuff
#elif defined(UNIX)
// do some cool Unix stuff
#else
#    error Unsupported operating system
#endif
Mecki
źródło
4

W MinGW _WIN32kontrola zdefiniowania nie działa. Oto rozwiązanie:

#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

Aby uzyskać więcej informacji, patrz: https://sourceforge.net/p/predef/wiki/OperatingSystems/

anakod
źródło
3
Świetny link. ---
MD XF,
2

Użyj #define OSsymboli #ifdef OSsymbol gdzie OSsymbol jest #definezdolnym symbolem identyfikującym twój docelowy system operacyjny.

Zazwyczaj należy dołączyć centralny plik nagłówka definiujący wybrany symbol systemu operacyjnego i używać specyficznych dla systemu operacyjnego katalogów włączeń i bibliotek do kompilacji i kompilacji.

Nie określiłeś swojego środowiska programistycznego, ale jestem prawie pewien, że Twój kompilator zapewnia globalne definicje popularnych platform i systemów operacyjnych.

Zobacz także http://en.wikibooks.org/wiki/C_Programming/Preprocessor

devio
źródło
2

Podsumowując, oto kilka przydatnych linków.

MD XF
źródło
2

Możesz użyć, Boost.Predefktóry zawiera różne predefiniowane makra dla platformy docelowej, w tym OS ( BOOST_OS_*). Tak, zwiększenie jest często uważane za bibliotekę C ++, ale ta jest nagłówkiem preprocesora, który również działa z C!

Ta biblioteka definiuje zestaw kompilatora, architektury, systemu operacyjnego, biblioteki i innych numerów wersji na podstawie informacji, które może gromadzić w predefiniowanych makrach C, C ++, Objective C i Objective C ++ lub w ogólnie dostępnych nagłówkach. Pomysł na tę bibliotekę zrodził się z propozycji rozszerzenia biblioteki Boost Config w celu zapewnienia większej liczby spójnych informacji niż obsługiwane przez nią definicje funkcji. Poniżej znajduje się zredagowana wersja tej krótkiej propozycji.

Na przykład

#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

Pełna lista znajduje się w BOOST_OSmakrach systemu operacyjnego

phuclv
źródło
1

Nie znalazłem tutaj definicji Haiku . Podsumowując, definicja Haiku-os jest prosta__HAIKU__

TadejP
źródło
0

Niektóre kompilatory wygenerują # definicje, które mogą ci w tym pomóc. Przeczytaj dokumentację kompilatora, aby ustalić, jakie są. MSVC definiuje taki, który jest __WIN32__, GCC ma jedne widać ztouch foo.h; gcc -dM foo.h

davenpcj
źródło
1
gcc: error: nierozpoznana opcja wiersza poleceń „--show-defines” gcc: błąd krytyczny: kompilacja plików wejściowych nie została zakończona.
Sebi2020,
0

Możesz użyć dyrektyw preprocesora jako ostrzeżenia lub błędu, aby sprawdzić w czasie kompilacji, że wcale nie musisz uruchamiać tego programu, po prostu go skompiluj .

#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
źródło
0

Napisałem małą bibliotekę, aby uzyskać system operacyjny, na którym jesteś, można go zainstalować przy użyciu clib (menedżera pakietów C), więc bardzo łatwo jest używać go jako zależności dla twoich projektów.

zainstalować

$ clib install abranhe/os.c

Stosowanie

#include <stdio.h>
#include "os.h"

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

Zwraca string ( char*) z nazwą używanego systemu operacyjnego, aby uzyskać więcej informacji na temat tego projektu, zapoznaj się z dokumentacją na Github .

Abraham Hernandez
źródło