Come posso controllare il sistema operativo con una direttiva preprocessore?


195

Ho bisogno del mio codice per fare cose diverse in base al sistema operativo su cui viene compilato. Sto cercando qualcosa del genere:

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

C'è un modo per fare questo? C'è un modo migliore per fare la stessa cosa?



8
@Cory Klein: No-no. questa domanda è stata posta anni prima
John_West

Si tratta di CnonC++
ilgaar

Risposte:


290

Il sito Macro predefinite per OS ha un elenco molto completo di controlli. Eccone alcuni, con collegamenti a dove sono stati trovati:

finestre

_WIN32   Solo 32 bit e 64 bit
_WIN64   64 bit

Unix (Linux, * BSD, Mac OS X)

Vedi questa domanda correlata su alcune delle insidie ​​dell'utilizzo di questo controllo.

unix
__unix
__unix__

Mac OS X

__APPLE__
__MACH__

Entrambi sono definiti; controllando per entrambi dovrebbe funzionare.

Linux

__linux__
linux Obsoleto (non conforme a POSIX)
__linuxObsoleto (non conforme a POSIX)

FreeBSD

__FreeBSD__

androide

__ANDROID__


1
Questo sito fornito non include iOS, quindi non riesce a distinguere tra iOS e OS X.
Gary Makin

2
Mac OS non definisce __unix__. Perché dovresti includerlo nell'elenco?
Victor Sergienko,

1
cpp -dM / dev / null ti fornirà un elenco di tutte le macro predefinite di gcc sulla tua versione di gcc installato
katta,

1
Cygwin definisce i unixsimboli e non definisce win32quelli, quindi fai attenzione. OTOH lo definisce __CYGWIN__.
David Dato

è __linux__uguale a __ANDROID__??
nessuno il

72

mostra GCC definisce su Windows:

gcc -dM -E - <NUL:

su Linux:

gcc -dM -E - </dev/null

Macro predefinite in MinGW:

WIN32 _WIN32 __WIN32 __WIN32__ __MINGW32__ WINNT __WINNT __WINNT__ _X86_ i386 __i386

su UNIX:

unix __unix__ __unix

1
Windows e Unices non sono i soli sistemi operativi
phuclv

35

Basato sul software nadeaus e sulla risposta di 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;
}

Testato con GCC e clang su:

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

il caro @MD XF, si prega di indicare le versioni di Windows, MinGW e Cygwin
PADYMKO

Windows 7 Enterprise 6.1.7601. Cygwin 2.7.0-1. Non riesco a trovare la versione di MinGW ma l'ho scaricata ieri.
MD XF

Probabilmente dovresti però essere informato: questo programma è standard C, quindi dovrebbe funzionare su tutti i sistemi conformi.
MD XF

caro @MD XF, grazie per queste informazioni. Ti ho aggiunto come collaboratore in cima a questa risposta.
PADYMKO

10

Nella maggior parte dei casi è meglio verificare se una determinata funzionalità è presente o meno. Ad esempio: se la funzione pipe()esiste o no.


3
c'è un modo semplice per verificare se una funzione è definita?
hayalci,

1
Se si utilizza autoconfig, è possibile verificare la presenza di funzioni con AC_CHECK_FUNCS (). AC_CHECK_FUNCS (pipe sqrt) definirà HAVE_PIPE e HAVE_SQRT se le funzioni sono disponibili. Non so come sia con altri strumenti di costruzione, ma suppongo che supportino anche questo in un certo senso.
Quinmars,

@MDXF A partire da C ++ 17, c'è __has_include. Non credo sia ancora standardizzato in C, ma tutti i principali compilatori (GCC, Clang, ICC, MSVC) lo implementano come un'estensione specifica del fornitore, anche in modalità 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

Le macro predefinite del compilatore Microsoft C / C ++ (MSVC) sono disponibili qui

Penso che tu stia cercando:

  • _WIN32- Definito come 1 quando la destinazione della compilazione è ARM a 32 bit, ARM a 64 bit, x86 o x64. Altrimenti, non definito
  • _WIN64- Definito come 1 quando la destinazione della compilazione è ARM a 64 bit o x64. Altrimenti, non definito.

Il compilatore gcc PreDefined MAcros può essere trovato qui

Penso che tu stia cercando:

  • __GNUC__
  • __GNUC_MINOR__
  • __GNUC_PATCHLEVEL__

Fai un google per i compilatori appropriati predefiniti.


4

Non esiste una macro standard impostata in base allo standard C. Alcuni compilatori C ne imposteranno uno su alcune piattaforme (ad esempio GCC con patch di Apple imposta una macro per indicare che si sta compilando su un sistema Apple e per la piattaforma Darwin). La tua piattaforma e / o il tuo compilatore C potrebbero impostare anche qualcosa, ma non esiste un modo generale.

Come ha detto hayalci, è meglio avere queste macro impostate nel tuo processo di compilazione in qualche modo. È facile definire una macro con la maggior parte dei compilatori senza modificare il codice. Puoi semplicemente passare -D MACROa GCC, ad es

gcc -D Windows
gcc -D UNIX

E nel tuo codice:

#if defined(Windows)
// do some cool Windows stuff
#elif defined(UNIX)
// do some cool Unix stuff
#else
#    error Unsupported operating system
#endif

4

Su MinGW, il _WIN32controllo di definizione non funziona. Ecco una soluzione:

#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

Per ulteriori informazioni, consultare: https://sourceforge.net/p/predef/wiki/OperatingSystems/


3
Ottimo collegamento ---
MD XF

2

Utilizzare #define OSsymbole #ifdef OSsymbol dove OSsymbol è a#define 'simbolo in grado di identificare il sistema operativo di destinazione.

In genere si dovrebbe includere un file di intestazione centrale che definisce il simbolo del sistema operativo selezionato e utilizzare le directory di inclusione e libreria specifiche del sistema operativo per compilare e compilare.

Non hai specificato il tuo ambiente di sviluppo, ma sono abbastanza sicuro che il tuo compilatore fornisca definizioni globali per piattaforme e sistemi operativi comuni.

Vedi anche http://en.wikibooks.org/wiki/C_Programming/Preprocessor




2

Puoi usare Boost.Predef contenente varie macro predefinite per la piattaforma di destinazione, incluso il sistema operativo ( BOOST_OS_*). Sì, boost è spesso pensato come una libreria C ++, ma questa è un'intestazione del preprocessore che funziona anche con C!

Questa libreria definisce un set di compilatore, architettura, sistema operativo, libreria e altri numeri di versione dalle informazioni che può raccogliere di macro predefinite C, C ++, Objective C e Objective C ++ o quelle definite nelle intestazioni generalmente disponibili. L'idea di questa libreria è nata da una proposta di estensione della libreria Boost Config per fornire informazioni più e coerenti rispetto alle definizioni delle funzionalità supportate. Quella che segue è una versione modificata di quella breve proposta.

Per esempio

#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

L'elenco completo è disponibile nelle BOOST_OSmacro del sistema operativo


1

Non ho trovato la definizione di Haiku qui. Per essere completo, la definizione di Haiku-os è semplice__HAIKU__


0

Alcuni compilatori genereranno #define che possono aiutarti in questo. Leggi la documentazione del compilatore per determinare quali sono. MSVC ne definisce uno __WIN32__, GCC ne ha alcuni con cui puoi vederetouch foo.h; gcc -dM foo.h


1
gcc: errore: opzione della riga di comando non riconosciuta '--show-definisce' gcc: errore fatale: nessuna compilazione dei file di input terminata.
Sebi2020,

0

È possibile utilizzare le direttive pre-processore come avvertimento o errore per verificare in fase di compilazione che non è necessario eseguire questo programma semplicemente compilandolo .

#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

Ho scritto una piccola libreria per ottenere il sistema operativo in cui ti trovi, può essere installato tramite clib (The C package manager), quindi è davvero semplice usarlo come dipendenza per i tuoi progetti.

Installare

$ clib install abranhe/os.c

uso

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

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

Restituisce una stringa ( char*) con il nome del sistema operativo in uso, per ulteriori informazioni su questo progetto consulta la documentazione su Github .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.