ทำไม#if
เงื่อนไขในรหัสต่อไปนี้ถึงเป็นจริง:
#include <iostream>
#define VALUE foo
int main() {
#if VALUE == bar
std::cout << "WORKS!" << std::endl;
#endif // VALUE
}
ทำไม#if
เงื่อนไขในรหัสต่อไปนี้ถึงเป็นจริง:
#include <iostream>
#define VALUE foo
int main() {
#if VALUE == bar
std::cout << "WORKS!" << std::endl;
#endif // VALUE
}
คำตอบ:
หลังจากการขยายและการประเมินแมโครทั้งหมดที่กำหนดและนิพจน์ __has_include (ตั้งแต่ C ++ 17) ตัวบ่งชี้ใด ๆ ที่ไม่ใช่ตัวอักษรบูลีนจะถูกแทนที่ด้วยตัวเลข 0 (ซึ่งรวมถึงตัวระบุที่เป็นคำหลัก lexically แต่ไม่ใช่โทเค็นทางเลือกเช่น )
ดังนั้นทั้งสองfoo
และbar
ถูกแทนที่ด้วย 0
ใน#if
คำสั่งระบุใด ๆ ที่ยังคงอยู่หลังจากเปลี่ยนตัวมาโคร (ยกเว้นtrue
และfalse
) 0
จะถูกแทนที่ด้วยอย่างต่อเนื่อง ดังนั้นคำสั่งของคุณจะกลายเป็น
#if 0 == 0
อันไหนจริง.
นี่เป็นเพราะไม่ได้foo
หรือไม่bar
ได้รับการกำหนดหรือค่าใด ๆ - ดังนั้นพวกเขาจะเหมือนกัน (เช่นแทนที่ด้วยค่า "0") คอมไพเลอร์จะให้คำเตือนเกี่ยวกับเรื่องนี้
MSVC
คอมไพเลอร์ (Visual Studio 2019) ให้ต่อไปนี้:
เตือน C4668: 'foo' ไม่ได้ถูกกำหนดเป็นมาโครตัวประมวลผลล่วงหน้าแทนที่ด้วย '0' สำหรับ '# if / # elif'
คำเตือน C4668: 'bar' ไม่ได้ถูกกำหนดให้เป็นมาโครตัวประมวลผลล่วงหน้าแทนที่ด้วย '0' สำหรับ '#if / # elif'
ดังนั้นVALUE
จะได้รับค่า '0' (ค่าเริ่มต้นสำหรับfoo
) และbar
ยังมี '0' ดังนั้นVALUE == bar
ประเมินเป็น "TRUE"
ในทำนองเดียวกันclang-cl
ให้สิ่งต่อไปนี้:
คำเตือน: ไม่ได้กำหนด 'foo' ประเมินเป็น 0 [-Wundef]
คำเตือน: ไม่ได้กำหนด 'bar' ให้ประเมินเป็น 0 [-Wundef]
MSVC
และclang-cl
คอมไพเลอร์คำเตือนนี้สามารถปิดการใช้งาน (ไม่ว่าจะโดยเฉพาะหรือโดยการตั้งค่า 'ระดับ' คำเตือนที่เหมาะสม)
เมื่อต้องการบรรลุสิ่งที่คุณเป็นให้ลองทำดังนี้:
#include <iostream>
#define DEBUG
int main() {
#ifdef DEBUG
std::cout << "WORKS!" << std::endl;
#endif
}
ในกรณีนี้คุณสามารถปิดคำสั่งการดีบักได้โดยเปลี่ยน "define" เป็น "undef"
#include <iostream>
#undef DEBUG
int main() {
#ifdef DEBUG
std::cout << "WORKS!" << std::endl;
#endif
}
คุณอาจพบว่าคอมไพเลอร์ของคุณช่วยให้คุณสามารถกำหนด DEBUG นอกรหัสตัวเอง ณ จุดที่คุณสามารถลดรหัสไป
#include <iostream>
int main() {
#ifdef DEBUG
std::cout << "WORKS!" << std::endl;
#endif
}
จากนั้นเรียกใช้คอมไพเลอร์ด้วยตัวเลือกเช่น -DDEBUG = 0
ลองดูบทเกี่ยวกับการตั้งโปรแกรมการป้องกันใน Steve McConnell "Code Complete"