Como verifico o SO com uma diretiva de pré-processador?

195

Eu preciso do meu código para fazer coisas diferentes com base no sistema operacional no qual é compilado. Estou procurando algo parecido com isto:

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

Existe uma maneira de fazer isso? Existe uma maneira melhor de fazer a mesma coisa?

perimosocordiae
fonte
1
possível duplicata de C ++ compilar em Windows e Linux: interruptor ifdef
Cory Klein
8
@Cory Klein: Não, não. esta pergunta foi feita anos antes
John_West 3/16
Isto é sobre CnãoC++
ilgaar

Respostas:

289

O site Predefined Macros for OS possui uma lista muito completa de verificações. Aqui estão alguns deles, com links para onde eles são encontrados:

janelas

_WIN32   32 e 64 bits
_WIN64   Somente 64 bits

Unix (Linux, * BSD, Mac OS X)

Veja esta pergunta relacionada em algumas das armadilhas do uso dessa verificação.

unix
__unix
__unix__

Mac OS X

__APPLE__
__MACH__

Ambos são definidos; a verificação de qualquer um deve funcionar.

Linux

__linux__
linux Obsoleto (não compatível com POSIX)
__linuxObsoleto (não compatível com POSIX)

FreeBSD

__FreeBSD__

Android

__ANDROID__

Lambda Fairy
fonte
1
Este site dado não inclui iOS, por isso deixa de ser capaz de distinguir entre iOS e OS X.
Gary Makin
2
Mac OS não define __unix__. Por que você o incluiria na lista?
Victor Sergienko
1
CPP -dm / dev / null vai lhe dar uma lista de todos os macro predefinidos do gcc da sua versão do gcc instalado
katta
1
Cygwin define os unixsímbolos e não os define win32, portanto, tenha cuidado. OTOH ele define __CYGWIN__.
David Given
é o __linux__mesmo que __ANDROID__??
noone
72

mostre o GCC define no Windows:

gcc -dM -E - <NUL:

no Linux:

gcc -dM -E - </dev/null

Macros predefinidas no MinGW:

WIN32 _WIN32 __WIN32 __WIN32__ __MINGW32__ WINNT __WINNT __WINNT__ _X86_ i386 __i386

no UNIX:

unix __unix__ __unix
qwer
fonte
1
Windows e Unices não são os únicos sistemas operacionais
phuclv
34

Baseado no nadeausoftware e na resposta da 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;
}

Testado com o GCC e clang em:

  • Debian 8
  • Windows (MinGW)
  • Windows (Cygwin)
PADYMKO
fonte
o querido @MD XF, indique as versões do seu Windows, MinGW e Cygwin
PADYMKO
Windows 7 Enterprise 6.1.7601. Cygwin 2.7.0-1. Não consigo encontrar a versão do MinGW, mas fiz o download ontem.
MD XF
Você provavelmente deve estar ciente - esse programa é padrão C, portanto deve funcionar em todos os sistemas compatíveis.
MD XF
Caro @MD XF, obrigado por esta informação. Adicionei você como colaborador em cima desta resposta.
PADYMKO
10

Na maioria dos casos, é melhor verificar se uma determinada funcionalidade está presente ou não. Por exemplo: se a função pipe()existe ou não.

quinmars
fonte
3
existe uma maneira fácil de verificar se uma função está definida?
hayalci 26/09/08
1
Se você estiver usando o autoconfig, poderá verificar as funções com AC_CHECK_FUNCS (). AC_CHECK_FUNCS (pipe sqrt) definirá HAVE_PIPE e HAVE_SQRT se as funções estiverem disponíveis. Não sei como é com outras ferramentas de construção, mas acho que elas também suportam isso de certa forma.
quinmars 27/09/08
@MDXF A partir do C ++ 17, existe __has_include. Não acho que seja padronizado em C ainda, mas todos os principais compiladores (GCC, Clang, ICC, MSVC) o implementam como uma extensão específica do fornecedor, mesmo no modo 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
fonte
5

Macros predefinidas do Microsoft C / C ++ compiler (MSVC) podem ser encontradas aqui

Eu acho que você está procurando:

  • _WIN32- Definido como 1 quando o destino da compilação for ARM de 32 bits, ARM de 64 bits, x86 ou x64. Caso contrário, indefinido
  • _WIN64- Definido como 1 quando o destino da compilação for ARM de 64 bits ou x64. Caso contrário, indefinido.

O compilador gcc PreDefined MAcros pode ser encontrado aqui

Eu acho que você está procurando:

  • __GNUC__
  • __GNUC_MINOR__
  • __GNUC_PATCHLEVEL__

Faça um google para seus compiladores apropriados predefinidos.

Martin York
fonte
4

Não há macro padrão definida de acordo com o padrão C. Alguns compiladores C definirão um em algumas plataformas (por exemplo, o GCC corrigido da Apple define uma macro para indicar que está compilando em um sistema Apple e para a plataforma Darwin). Sua plataforma e / ou seu compilador C podem definir algo também, mas não há uma maneira geral.

Como hayalci disse, é melhor ter essas macros definidas no seu processo de criação de alguma forma. É fácil definir uma macro com a maioria dos compiladores sem modificar o código. Você pode simplesmente passar -D MACROpara o GCC, ou seja,

gcc -D Windows
gcc -D UNIX

E no seu código:

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

No MinGW, a _WIN32verificação de definição não está funcionando. Aqui está uma solução:

#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

Para mais informações, consulte: https://sourceforge.net/p/predef/wiki/OperatingSystems/

anakod
fonte
3
Ótimo link. ---
MD XF
2

Use #define OSsymbole #ifdef OSsymbol onde OSsymbol é um#define símbolo 'capaz de identificar seu SO de destino.

Normalmente, você incluiria um arquivo de cabeçalho central definindo o símbolo do sistema operacional selecionado e usaria os diretórios de inclusão e biblioteca específicos do sistema operacional para compilar e construir.

Você não especificou seu ambiente de desenvolvimento, mas tenho certeza de que seu compilador fornece definições globais para plataformas e sistemas operacionais comuns.

Veja também http://en.wikibooks.org/wiki/C_Programming/Preprocessor

devio
fonte
2

Apenas para resumir tudo, aqui estão alguns links úteis.

MD XF
fonte
2

Você pode usar o Boost.Predefque contém várias macros predefinidas para a plataforma de destino, incluindo o SO ( BOOST_OS_*). Sim, o aumento é geralmente considerado uma biblioteca C ++, mas este é um cabeçalho de pré-processador que também funciona com C!

Esta biblioteca define um conjunto de compilador, arquitetura, sistema operacional, biblioteca e outros números de versão a partir das informações que pode coletar de macros predefinidas em C, C ++, Objective C e Objective C ++ ou aquelas definidas nos cabeçalhos geralmente disponíveis. A idéia para esta biblioteca surgiu de uma proposta de estender a biblioteca Boost Config para fornecer informações mais consistentes do que as definições de recursos que ela suporta. O que se segue é uma versão editada dessa breve proposta.

Por exemplo

#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

A lista completa pode ser encontrada nas BOOST_OSmacros do sistema operacional

phuclv
fonte
1

Não encontrei a definição de haicais aqui. Para ser completa, a definição do Haiku-os é simples__HAIKU__

TadejP
fonte
0

Alguns compiladores geram #defines que podem ajudá-lo com isso. Leia a documentação do compilador para determinar o que são. MSVC define um que é __WIN32__, o GCC tem alguns que você pode ver comtouch foo.h; gcc -dM foo.h

davenpcj
fonte
1
gcc: error: opção de linha de comando não reconhecida '--show-define' gcc: erro fatal: nenhuma compilação de arquivos de entrada finalizada.
Sebi2020
0

Você pode usar as diretivas do pré-processador como aviso ou erro para verificar, no tempo de compilação, se você não precisa executar este programa, simplesmente compile -o.

#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
fonte
0

Eu escrevi uma pequena biblioteca para obter o sistema operacional em que você está, ele pode ser instalado usando o clib (gerenciador de pacotes C), por isso é muito simples de usá-lo como uma dependência para seus projetos.

Instalar

$ clib install abranhe/os.c

Uso

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

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

Ele retorna uma string ( char*) com o nome do sistema operacional que você está usando, para obter mais informações sobre este projeto, consulte a documentação no Github .

Abraham Hernandez
fonte