Apa sebenarnya yang dilakukan oleh blok #if 0… #endif?

124

Dalam C / C ++

Apa yang terjadi pada kode yang ditempatkan di antara blok #if 0/ #endif?

#if 0

//Code goes here

#endif

Apakah kode tersebut dilewati begitu saja dan karena itu tidak dieksekusi?

vette982
sumber
17
Ini adalah teknik yang digunakan untuk mengomentari sejumlah besar kode atau untuk memungkinkan pengujian penyertaan blok kode. Tanpa fitur ini, seseorang harus //mengawali setiap baris dengan atau memulai bagian dengan /*dan mengakhiri bagian dengan */. Masalah dengan teknik terakhir adalah komentar tidak bersarang sehingga pengembang harus memeriksa dan menangani apa pun di */antara awal dan akhir.
Thomas Matthews
1
kemungkinan duplikat dari Mengapa seseorang menggunakan arahan preprocessor if 1 c
P Shved

Jawaban:

141

Tidak hanya tidak dieksekusi, bahkan tidak bisa dikompilasi.

#ifadalah perintah preprocessor, yang dievaluasi sebelum langkah kompilasi sebenarnya. Kode di dalam blok itu tidak muncul di biner yang dikompilasi.

Ini sering digunakan untuk menghapus segmen kode sementara dengan tujuan untuk mengaktifkannya kembali nanti.

David
sumber
1
Ini berlaku untuk semua jenis komentar. Perbedaan penting adalah bersarang.
Samy Bencherif
73

Ini identik dengan mengomentari blok, kecuali dengan satu perbedaan penting: Bersarang tidak menjadi masalah. Pertimbangkan kode ini:

foo();
bar(x, y); /* x must not be NULL */
baz();

Jika saya ingin berkomentar, saya mungkin mencoba:

/*
foo();
bar(x, y); /* x must not be NULL */
baz();
*/

Bzzt. Kesalahan sintaks! Mengapa? Karena komentar blok tidak bersarang, sehingga (seperti yang Anda lihat dari penyorotan sintaks SO) kata */setelah "NULL" mengakhiri komentar, membuat bazpanggilan tidak dikomentari, dan */setelah bazkesalahan sintaks. Di samping itu:

#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif

Berfungsi untuk mengomentari semuanya. Dan #if 0s akan bersarang satu sama lain, seperti ini:

#if 0
pre_foo();
#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif
quux();
#endif

Meskipun tentu saja ini bisa sedikit membingungkan dan menjadi sakit kepala pemeliharaan jika tidak dikomentari dengan benar.

Tyler McHenry
sumber
5
Perhatikan bahwa kode di dalam #if harus benar secara leksikal (berlawanan dengan komentar) dan arahan preprocessor masih berlaku (ditto).
jpalecek
@David: Ini tidak benar secara leksikal, tetapi masih akan dikompilasi. Jadi kodenya tidak harus benar secara leksikal.
Dennis Zickefoose
1
@ Dennis, saya dapatkan foo.c:3: unterminated string or character constantdari gcc, apa yang Anda gunakan?
David X
18

Ini secara permanen mengomentari kode itu sehingga kompiler tidak akan pernah mengkompilasinya.

Pembuat kode nanti dapat mengubah #ifdef agar kode tersebut dikompilasi dalam program jika dia mau.

Ini persis seperti kodenya tidak ada.

Nilbert
sumber
15

Apa sebenarnya yang dilakukan oleh blok #if 0… #endif?

Ini memberi tahu Anda bahwa penulis jelas belum pernah mendengar tentang sistem kontrol versi. Yang, pada gilirannya, memberitahu Anda untuk lari sejauh mungkin…

Jörg W Mittag
sumber
12

Saya ingin menambahkan untuk #elsekasus ini:

#if 0
   /* Code here will NOT be complied. */
#else
   /* Code will be compiled. */
#endif


#if 1
   /* Code will be complied. */
#else
   /* Code will NOT be compiled. */
#endif
Steven Xu
sumber
7

Ketika preprocessor melihat #if itu memeriksa apakah token berikutnya memiliki nilai bukan nol. Jika ya, ia menyimpan kode untuk kompilator. Jika tidak, ia akan menghapus kode itu sehingga kompilator tidak pernah melihatnya.

Jika seseorang mengatakan # jika 0 mereka secara efektif mengomentari kode sehingga tidak akan pernah dapat dikompilasi. Anda dapat menganggap ini sama seperti jika mereka meletakkan / * ... * / di sekitarnya. Ini tidak persis sama, tetapi memiliki efek yang sama.

Jika Anda ingin memahami apa yang terjadi secara mendetail, Anda sering dapat melihatnya. Banyak kompiler akan mengizinkan Anda untuk melihat file-file tersebut setelah preprocessor dijalankan. Misalnya, pada Visual C ++, perintah switch / P akan menjalankan preprocessor dan memasukkan hasilnya ke dalam file .i.

Steve Rowe
sumber
Tidak terlalu. Praprosesor mem-parsing menurut baris, bukan dengan token. Menurut penjelasan Anda, tidak mungkin untuk mengatakan misalnya #if WIN32 || __CYGWIN__tetapi ini berfungsi seperti yang diharapkan.
Ben Voigt
Saya menyederhanakan. Jika ada atau, itu akan memeriksa apakah salah satu token bukan nol. Begitu juga jika ada dan akan mengecek apakah keduanya bukan nol.
Steve Rowe
3

Baris yang diawali dengan a #adalah arahan preprocessor . #if 0 [...] #endifblok tidak sampai ke kompiler dan tidak akan menghasilkan kode mesin.

Anda dapat mendemonstrasikan apa yang terjadi dengan preprocessor dengan file sumber ifdef.cxx:

#if 0
This code will not be compiled
#else
int i = 0;
#endif

Berjalan gcc -E ifdef.cxxakan menunjukkan kepada Anda apa yang telah dikompilasi.

Anda dapat memilih untuk menggunakan mekanisme ini untuk mencegah blok kode dikompilasi selama siklus pengembangan, tetapi Anda mungkin tidak ingin memeriksanya ke kontrol sumber karena hanya menambahkan cruft ke kode Anda dan mengurangi keterbacaan. Jika itu adalah bagian kode sejarah yang telah dikomentari, maka itu harus dihapus: kontrol sumber berisi riwayatnya, bukan?

Juga, jawabannya mungkin sama untuk C dan C ++ tetapi tidak ada bahasa yang disebut C / C ++ dan itu bukan kebiasaan yang baik untuk merujuk ke bahasa seperti itu.

Johnsyweb
sumber
4
Apa salahnya mengatakan C / C ++ sebagai singkatan dari "C atau C ++"? Apakah Anda benar-benar berpikir ada orang yang akan bingung berpikir bahwa ada bahasa yang disebut "C / C ++"?
Christopher Barber
1
@ Chris: Orang-orang terus-menerus mengajukan pertanyaan seperti "Bagaimana cara melakukan X di C / C ++?" Yang merupakan pertanyaan yang tidak masuk akal; Anda sedang membuat kode dalam satu atau lainnya, dan jika Anda belum memilih, Anda harus menjelaskan fakta itu secara eksplisit. Jadi, ya, orang bingung ada bahasa yang disebut "C / C ++"
Dennis Zickefoose
1
Sungguh pernyataan yang tidak masuk akal! Ada ribuan pertanyaan yang jawabannya relevan dengan C dan C ++. Ingatlah bahwa ini adalah situs untuk mengajukan pertanyaan. Hanya karena Anda mengajukan pertanyaan umum bukan berarti Anda tidak tahu bahasa apa yang Anda gunakan. Jika Anda menduga demikian, seperti dalam pertanyaan ini, bagaimana cara membantu menentukan C atau C ++? Apakah menurut Anda akan membantu jika setiap pertanyaan yang dapat diterapkan pada C atau C ++ ditanyakan dua kali?
Christopher Barber
@ Christopher: Anda benar, ada banyak pertanyaan di mana jawabannya sama relevannya dengan C, C ++ dan Objective-C (ini salah satunya). Stack Overflow memiliki sistem penandaan yang berguna untuk menunjukkan bahasa mana yang dimiliki pertanyaan. Seperti yang @Dennis sebutkan, SO (dan forum pemrograman lain [fora?]) Ada (terlalu) banyak orang yang bingung tentang penggambaran antara C dan bahasa turunan C lainnya yang merujuk ke bahasa ini secara bergantian sebagai C / C ++ membuatnya lebih sulit untuk menjawab pertanyaan dalam bahasa yang sesuai.
Johnsyweb
2

Tidak terlalu

int main(void)
{
   #if 0
     the apostrophe ' causes a warning
   #endif
   return 0;
}

Ini menunjukkan "tc: 4: 19: peringatan: tidak ada terminating 'karakter" dengan gcc 4.2.4

Arthur Kalliokoski
sumber
2
Peringatan ini dibuat oleh preprocessor, bukan compiler. Kompilator hanya dapat melihat: # 1 "tc" # 1 "<built-in>" # 1 "<command-line>" # 1 "tc" int main (void) {return 0; }
Johnsyweb
0

Ini adalah cara yang murah untuk berkomentar, tetapi saya curiga itu bisa memiliki potensi debugging. Misalnya, Anda memiliki build yang menghasilkan nilai ke file. Anda mungkin tidak menginginkannya dalam versi final sehingga Anda dapat menggunakan #if 0 ... #endif.

Juga, saya menduga cara yang lebih baik untuk melakukannya untuk tujuan debug adalah dengan melakukan:

#ifdef DEBUG
// output to file
#endif

Anda dapat melakukan sesuatu seperti itu dan itu mungkin lebih masuk akal dan yang harus Anda lakukan hanyalah menentukan DEBUG untuk melihat hasilnya.

Daniel
sumber