Perbandingan makro jika-direktif

25

Mengapa #ifkondisi dalam kode berikut terpenuhi:

#include <iostream>
#define VALUE foo    

int main() {    
#if VALUE == bar
    std::cout << "WORKS!" << std::endl;
#endif // VALUE
}
michalt38
sumber

Jawaban:

26

The halaman di cppreference.com negara:

Setelah semua ekspansi makro dan evaluasi ekspresi yang didefinisikan dan __has_include (karena C ++ 17), pengidentifikasi apa pun yang bukan boolean literal diganti dengan angka 0 (ini termasuk pengidentifikasi yang merupakan kata kunci leksikal, tetapi bukan token alternatif seperti dan ).

Jadi keduanya foodan bardiganti dengan 0.

BessieTheCow
sumber
Bagaimana dengan C ++ 98, C ++ 03, C ++ 11 dan C ++ 14?
kelalaka
1
@kalalaka Semuanya sama saja. Sudah seperti itu sejak C89.
SS Anne
1
@kelalaka Bagian "sejak C ++ 17" hanya mengacu pada bagian "dan __has_include". Sebelum C ++ 17 itu sama, hanya saja bagian itu dihilangkan.
BessieTheCow
15

Dalam sebuah #ifpernyataan, setiap pengidentifikasi yang tetap setelah substitusi makro (kecuali untuk truedan false) diganti dengan konstanta 0. Jadi arahan Anda menjadi

#if 0 == 0

yang mana yang benar.

1201ProgramAlarm
sumber
Untuk memperjelas, '#define VALUE foo' mendefinisikan simbol 'VALUE' untuk menyelesaikan ke nilai yang sama dengan simbol 'foo', tetapi simbol 'foo' tidak memiliki arti, sehingga akan ditafsirkan sebagai 0.
ManicDee
14

Ini karena keduanya belum foojuga bardiberikan definisi atau nilai - sehingga keduanya sama (yaitu diganti dengan nilai "0"). Compiler akan memberi peringatan tentang hal ini.

The MSVCcompiler (Visual Studio 2019) memberikan berikut:

peringatan C4668: 'foo' tidak didefinisikan sebagai makro preprosesor, diganti dengan '0' untuk '# if / # elif'
peringatan C4668: 'bar' tidak didefinisikan sebagai makro praprosesor, diganti dengan '0' untuk '#jika / # elif '

Jadi VALUEdiberi nilai '0' (default untuk foo) dan barjuga memiliki '0', jadi VALUE == bardievaluasi menjadi "BENAR."

Demikian pula, clang-clberikan yang berikut:

peringatan: 'foo' tidak didefinisikan, mengevaluasi ke 0 [-Wundef]
peringatan: 'bar' tidak didefinisikan, mengevaluasi ke 0 [-Wundef]

Adrian Mole
sumber
Apakah peringatan itu wajib atau itu adalah fitur dari kompiler?
kelalaka
1
@kelalaka Sepengetahuan saya, tidak ada 'peringatan' kompiler wajib! Bahkan dengan MSVCdan clang-clpenyusun, peringatan ini dapat dinonaktifkan (baik secara khusus, atau dengan menetapkan 'level' peringatan yang sesuai).
Adrian Mole
0

Untuk mencapai apa yang Anda kejar, coba ini:

#include <iostream>
#define DEBUG  

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Dalam hal ini Anda dapat mematikan pernyataan debugging dengan mengubah "define" menjadi "undef".

#include <iostream>
#undef DEBUG  

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Anda mungkin menemukan bahwa kompiler Anda memungkinkan Anda untuk mendefinisikan DEBUG di luar kode itu sendiri, di mana Anda dapat mengurangi kode tersebut

#include <iostream>

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Dan kemudian memanggil kompiler dengan opsi seperti -DDEBUG = 0

Lihatlah bab tentang Pemrograman Defensif di Steve McConnell, "Kode Lengkap."

ManicDee
sumber