Bagaimana cara saya memeriksa OS dengan arahan preprosesor?

195

Saya perlu kode saya untuk melakukan hal-hal yang berbeda berdasarkan sistem operasi yang dikompilasi. Saya mencari sesuatu seperti ini:

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

Apakah ada cara untuk melakukan ini? Apakah ada cara yang lebih baik untuk melakukan hal yang sama?

perimosocordiae
sumber
1
kemungkinan duplikat kompilasi C ++ di Windows dan Linux: ifdef switch
Cory Klein
8
@Cory Klein: Tidak-tidak. pertanyaan ini telah ditanyakan bertahun-tahun sebelumnya
John_West
Ini tentang CtidakC++
ilgaar

Jawaban:

290

The Predefined Macro untuk OS situs memiliki daftar yang sangat lengkap cek. Berikut adalah beberapa di antaranya, dengan tautan ke tempat mereka ditemukan:

Windows

_WIN32   Baik 32 bit dan 64 bit
_WIN64   64 bit saja

Unix (Linux, * BSD, Mac OS X)

Lihat pertanyaan terkait ini pada beberapa kesulitan menggunakan cek ini.

unix
__unix
__unix__

Mac OS X

__APPLE__
__MACH__

Keduanya didefinisikan; memeriksa apakah harus bekerja.

Linux

__linux__
linux Usang (tidak sesuai dengan POSIX)
__linux Sudah usang (tidak sesuai dengan POSIX)

FreeBSD

__FreeBSD__

Android

__ANDROID__

Lambda Fairy
sumber
1
Situs yang diberikan ini tidak termasuk iOS, jadi gagal membedakan antara iOS dan OS X.
Gary Makin
2
Mac OS tidak mendefinisikan __unix__. Mengapa Anda memasukkannya ke dalam daftar?
Victor Sergienko
1
cpp -dM / dev / null akan memberi Anda daftar semua makro yang telah ditentukan gcc pada versi gcc yang terpasang
katta
1
Cygwin mendefinisikan unixsimbol dan tidak mendefinisikan simbol win32, jadi berhati-hatilah. OTOH itu memang mendefinisikan __CYGWIN__.
David Diberi
adalah __linux__sama __ANDROID__??
noone
72

tampilkan definisi GCC di Windows:

gcc -dM -E - <NUL:

di Linux:

gcc -dM -E - </dev/null

Makro yang telah ditentukan sebelumnya di MinGW:

WIN32 _WIN32 __WIN32 __WIN32__ __MINGW32__ WINNT __WINNT __WINNT__ _X86_ i386 __i386

di UNIXes:

unix __unix__ __unix
qwer
sumber
1
Windows dan Unices bukan satu-satunya OS
phuclv
35

Berdasarkan nadeausoftware dan jawaban 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;
}

Diuji dengan GCC dan dentang:

  • Debian 8
  • Windows (MinGW)
  • Windows (Cygwin)
PADYMKO
sumber
@MD XF sayang, harap tunjukkan versi Windows, MinGW, dan Cygwin Anda
PADYMKO
Windows 7 Enterprise 6.1.7601. Cygwin 2.7.0-1. Saya tidak dapat menemukan versi MinGW tetapi saya mengunduhnya kemarin.
MD XF
Anda mungkin harus dibuat sadar - program ini adalah standar C, sehingga harus bekerja pada semua sistem yang sesuai.
MD XF
@MD XF sayang, terima kasih atas informasi ini. Saya menambahkan Anda sebagai kontributor di atas jawaban ini.
PADYMKO
10

Dalam kebanyakan kasus, lebih baik untuk memeriksa apakah fungsionalitas yang diberikan ada atau tidak. Misalnya: apakah fungsi itu pipe()ada atau tidak.

quinmars
sumber
3
apakah ada cara mudah untuk memeriksa apakah suatu fungsi didefinisikan?
hayalci
1
Jika Anda menggunakan autoconfig Anda dapat memeriksa fungsi dengan AC_CHECK_FUNCS (). AC_CHECK_FUNCS (pipa sqrt) akan mendefinisikan HAVE_PIPE dan HAVE_SQRT jika fungsinya tersedia. Saya tidak tahu bagaimana dengan alat bangunan lain, tapi saya kira mereka juga mendukungnya.
quinmars
@ MDXF Pada C ++ 17, ada __has_include. Saya tidak berpikir itu standar dalam C, tetapi semua kompiler utama (GCC, Dentang, ICC, MSVC) mengimplementasikannya sebagai ekstensi khusus vendor, bahkan dalam mode 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
sumber
5

Macro Standar Microsoft C / C ++ (MSVC) yang telah ditentukan dapat ditemukan di sini

Saya pikir Anda mencari:

  • _WIN32- Ditetapkan sebagai 1 ketika target kompilasi adalah ARM 32-bit, ARM 64-bit, x86, atau x64. Kalau tidak, tidak ditentukan
  • _WIN64- Ditetapkan sebagai 1 saat target kompilasi adalah ARM 64-bit atau x64. Kalau tidak, tidak ditentukan.

kompiler gcc PreDefined MAcros dapat ditemukan di sini

Saya pikir Anda mencari:

  • __GNUC__
  • __GNUC_MINOR__
  • __GNUC_PATCHLEVEL__

Lakukan google untuk kompiler yang sesuai yang telah ditentukan sebelumnya.

Martin York
sumber
4

Tidak ada standar makro yang diatur sesuai dengan standar C. Beberapa kompiler C akan menetapkan satu pada beberapa platform (misalnya GCC yang ditambal Apple menetapkan makro untuk menunjukkan bahwa ia mengkompilasi pada sistem Apple dan untuk platform Darwin). Platform Anda dan / atau kompiler C Anda mungkin mengatur sesuatu juga, tetapi tidak ada cara umum.

Seperti kata hayalci, yang terbaik adalah mengatur makro ini dalam proses pembuatan Anda. Mudah untuk mendefinisikan makro dengan sebagian besar kompiler tanpa memodifikasi kode. Anda dapat dengan mudah berpindah -D MACROke GCC, yaitu

gcc -D Windows
gcc -D UNIX

Dan dalam kode Anda:

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

Pada MinGW, _WIN32centang define tidak berfungsi. Inilah solusinya:

#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

Untuk informasi lebih lanjut, lihat: https://sourceforge.net/p/predef/wiki/OperatingSystems/

anakod
sumber
3
Tautan bagus. ---
MD XF
2

Gunakan #define OSsymboldan di #ifdef OSsymbol mana OSsymbol adalah #definesimbol yang dapat mengidentifikasi OS target Anda.

Biasanya Anda akan menyertakan file header pusat yang mendefinisikan simbol OS yang dipilih dan menggunakan direktori dan perpustakaan spesifik OS untuk mengkompilasi dan membangun.

Anda tidak menentukan lingkungan pengembangan Anda, tapi saya cukup yakin kompiler Anda memberikan definisi global untuk platform dan OS umum.

Lihat juga http://en.wikibooks.org/wiki/C_Programming/Preprocessor

devio
sumber
2

Singkatnya, berikut adalah banyak tautan bermanfaat.

MD XF
sumber
2

Anda dapat menggunakan Boost.Predefyang berisi berbagai makro yang telah ditentukan sebelumnya untuk platform target termasuk OS ( BOOST_OS_*). Ya, peningkatan sering dianggap sebagai pustaka C ++, tetapi yang ini adalah tajuk preprosesor yang bekerja dengan C juga!

Pustaka ini mendefinisikan sekumpulan kompiler, arsitektur, sistem operasi, pustaka, dan nomor versi lainnya dari informasi yang dapat dikumpulkannya dari makro yang telah ditentukan C, C ++, Objective C, dan Objective C ++ atau yang didefinisikan dalam header yang tersedia secara umum. Gagasan untuk perpustakaan ini muncul dari proposal untuk memperluas perpustakaan Boost Config untuk memberikan lebih banyak, dan konsisten, informasi daripada definisi fitur yang didukungnya. Berikut ini adalah versi yang diedit dari proposal singkat itu.

Sebagai contoh

#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

Daftar lengkap dapat ditemukan di BOOST_OSmakro sistem operasi

phuclv
sumber
1

Saya tidak menemukan definisi Haiku di sini. Agar lengkap, definisi Haiku-os sederhana__HAIKU__

TadejP
sumber
0

Beberapa kompiler akan menghasilkan #define yang dapat membantu Anda dengan ini. Baca dokumentasi kompiler untuk menentukan apa itu. MSVC mendefinisikan satu itu __WIN32__, GCC memiliki beberapa yang dapat Anda lihattouch foo.h; gcc -dM foo.h

davenpcj
sumber
1
gcc: error: opsi baris perintah yang tidak dikenal '--show-mendefinisikan' gcc: kesalahan fatal: tidak ada kompilasi file input yang dihentikan.
Sebi2020
0

Anda dapat menggunakan arahan pra-prosesor sebagai peringatan atau kesalahan untuk memeriksa pada waktu kompilasi Anda tidak perlu menjalankan program ini sama sekali, cukup kompilasi saja.

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

Saya menulis perpustakaan kecil untuk mendapatkan sistem operasi tempat Anda berada, dapat diinstal menggunakan clib (manajer paket C), jadi sangat mudah untuk menggunakannya sebagai ketergantungan untuk proyek Anda.

Install

$ clib install abranhe/os.c

Pemakaian

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

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

Ini mengembalikan string ( char*) dengan nama sistem operasi yang Anda gunakan, untuk informasi lebih lanjut tentang proyek ini, periksa dokumentasi di Github .

Abraham Hernandez
sumber