Ini tampaknya merupakan "ekstensi GNU" (tidak berdokumen):[koreksi :Saya akhirnya menemukan penyebutan di dokumen. Lihat di bawah.]
Perintah berikut menggunakan -dM
opsi untuk mencetak semua definisi preprocessor; karena input "file" kosong, itu menunjukkan dengan tepat makro yang telah ditentukan. Itu dijalankan dengan gcc-4.7.3 pada instalasi ubuntu standar. Anda dapat melihat bahwa preprosesor sadar standar. Total ada 243 macro dengan -std=gnu99
dan 240 dengan -std=c99
; Saya memfilter output untuk relevansi.
$ cpp --std=c89 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
$ cpp --std=gnu89 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1
$ cpp --std=c99 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
$ cpp --std=gnu99 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1
Versi "standar gnu" juga #define unix
. (Menggunakan c11
dan gnu11
menghasilkan hasil yang sama.)
Saya kira mereka punya alasan, tetapi menurut saya membuat instalasi default gcc (yang mengkompilasi kode C dengan -std=gnu89
kecuali ditentukan lain) tidak sesuai, dan - seperti dalam pertanyaan ini - mengejutkan. Mencemari ruang nama global dengan makro yang namanya tidak dimulai dengan garis bawah tidak diizinkan dalam implementasi yang sesuai. (6.8.10p2:"Nama makro lainnya yang telah ditentukan sebelumnya harus dimulai dengan garis bawah di depan diikuti dengan huruf besar atau garis bawah kedua," tetapi, sebagaimana disebutkan dalam Lampiran J.5 (masalah portabilitas), nama tersebut sering kali telah ditentukan sebelumnya.)
Ketika saya awalnya menulis jawaban ini, saya tidak dapat menemukan dokumentasi apa pun di gcc tentang masalah ini, tetapi akhirnya saya menemukannya, bukan dalam perilaku yang ditentukan implementasi C atau dalam ekstensi C tetapi dalam cpp
manual bagian 3.7.3, yang mencatat bahwa:
Kami perlahan-lahan menghapus semua makro yang telah ditentukan sebelumnya yang berada di luar ruang nama yang dicadangkan. Anda tidak boleh menggunakannya dalam program baru…
Di Masa Lalu (pra-ANSI), simbol yang telah ditentukan sebelumnya seperti unix
dan vax
adalah cara untuk memungkinkan kode untuk mendeteksi pada waktu kompilasi untuk apa sistem itu dikompilasi. Tidak ada standar bahasa resmi saat itu (di luar bahan referensi di belakang edisi pertama K&R), dan kode C dengan kompleksitas apa pun biasanya berupa labirin kompleks #ifdef
s untuk memungkinkan perbedaan antara sistem. Definisi makro ini umumnya diatur oleh kompiler itu sendiri, tidak ditentukan dalam file header perpustakaan. Karena tidak ada aturan nyata tentang pengidentifikasi mana yang dapat digunakan oleh implementasi dan mana yang dicadangkan untuk pemrogram, penulis kompiler merasa bebas untuk menggunakan nama sederhana seperti unix
dan berasumsi bahwa pemrogram hanya akan menghindari penggunaan nama tersebut untuk tujuan mereka sendiri.
Standar ANSI C 1989 memperkenalkan aturan yang membatasi simbol apa yang dapat ditentukan sebelumnya oleh implementasi secara hukum. Makro yang ditentukan sebelumnya oleh kompiler hanya dapat memiliki nama yang diawali dengan dua garis bawah, atau dengan garis bawah diikuti dengan huruf besar, sehingga pemrogram bebas menggunakan pengidentifikasi yang tidak cocok dengan pola tersebut dan tidak digunakan di pustaka standar.
Akibatnya, setiap kompiler yang menentukan unix
atau linux
tidak sesuai, karena akan gagal mengkompilasi kode legal sempurna yang menggunakan sesuatu seperti int linux = 5;
.
Seperti yang terjadi, gcc tidak sesuai secara default -- tetapi dapat dibuat agar sesuai (cukup baik) dengan opsi baris perintah yang tepat:
gcc -std=c90 -pedantic ... # or -std=c89 or -ansi
gcc -std=c99 -pedantic
gcc -std=c11 -pedantic
Lihat manual gcc untuk detail lebih lanjut.
gcc akan menghapus definisi ini secara bertahap dalam rilis mendatang, jadi Anda sebaiknya tidak menulis kode yang bergantung padanya. Jika program Anda perlu mengetahui apakah sedang dikompilasi untuk target Linux atau tidak, program dapat memeriksa apakah __linux__
didefinisikan (dengan asumsi Anda menggunakan gcc atau kompiler yang kompatibel dengannya). Lihat manual praprosesor GNU C untuk informasi lebih lanjut.
Sisi yang sebagian besar tidak relevan:pemenang "Best One Liner" dari Kontes Kode C Internasional yang Dikaburkan tahun 1987, oleh David Korn (ya, penulis Korn Shell) memanfaatkan unix
yang telah ditentukan sebelumnya makro:
main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
Mencetak "unix"
, tetapi karena alasan yang sama sekali tidak ada hubungannya dengan ejaan nama makro.