เปรียบเทียบมาโคร if-directive


25

ทำไม#ifเงื่อนไขในรหัสต่อไปนี้ถึงเป็นจริง:

#include <iostream>
#define VALUE foo    

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

คำตอบ:


26

หน้า cppreference.comฯ :

หลังจากการขยายและการประเมินแมโครทั้งหมดที่กำหนดและนิพจน์ __has_include (ตั้งแต่ C ++ 17) ตัวบ่งชี้ใด ๆ ที่ไม่ใช่ตัวอักษรบูลีนจะถูกแทนที่ด้วยตัวเลข 0 (ซึ่งรวมถึงตัวระบุที่เป็นคำหลัก lexically แต่ไม่ใช่โทเค็นทางเลือกเช่น )

ดังนั้นทั้งสองfooและbarถูกแทนที่ด้วย 0


แล้ว C ++ 98, C ++ 03, C ++ 11 และ C ++ 14 ล่ะ?
kelalaka

1
@kelalaka มันเหมือนกันทั้งหมด มันเป็นอย่างนั้นมาตั้งแต่ C89
SS Anne

1
@kelalaka ส่วน "ตั้งแต่ C ++ 17" หมายถึงส่วน "และ __has_include" เท่านั้น ก่อนที่ C ++ 17 จะเหมือนกันเพียงแค่เว้นส่วนนั้น
BessieTheCow

15

ใน#ifคำสั่งระบุใด ๆ ที่ยังคงอยู่หลังจากเปลี่ยนตัวมาโคร (ยกเว้นtrueและfalse) 0จะถูกแทนที่ด้วยอย่างต่อเนื่อง ดังนั้นคำสั่งของคุณจะกลายเป็น

#if 0 == 0

อันไหนจริง.


ในการชี้แจง '#define VALUE foo' กำหนดสัญลักษณ์ 'VALUE' เพื่อแก้ไขค่าเดียวกันกับสัญลักษณ์ 'foo' แต่สัญลักษณ์ 'foo' ไม่มีความหมายดังนั้นจะตีความเป็น 0
ManicDee

14

นี่เป็นเพราะไม่ได้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]


คำเตือนบังคับหรือไม่นั้นเป็นคุณสมบัติของคอมไพเลอร์หรือไม่?
kelalaka

1
@kelalaka เพื่อความรู้ที่ดีที่สุดของฉันไม่มี 'คำเตือน' คอมไพเลอร์เป็นสิ่งจำเป็น! ถึงแม้จะมีMSVCและclang-clคอมไพเลอร์คำเตือนนี้สามารถปิดการใช้งาน (ไม่ว่าจะโดยเฉพาะหรือโดยการตั้งค่า 'ระดับ' คำเตือนที่เหมาะสม)
Adrian Mole

0

เมื่อต้องการบรรลุสิ่งที่คุณเป็นให้ลองทำดังนี้:

#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"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.