#ifdef vs #if - วิธีใดดีกว่า / ปลอดภัยกว่าสำหรับวิธีการเปิด / ปิดการรวบรวมโค้ดบางส่วน


112

นี่อาจเป็นเรื่องของรูปแบบ แต่มีความแตกแยกเล็กน้อยในทีม dev ของเราและฉันสงสัยว่ามีใครมีความคิดเกี่ยวกับเรื่องนี้บ้าง ...

โดยทั่วไปเรามีคำสั่งพิมพ์ดีบักซึ่งเราปิดในระหว่างการพัฒนาตามปกติ โดยส่วนตัวแล้วฉันชอบทำสิ่งต่อไปนี้:

//---- SomeSourceFile.cpp ----

#define DEBUG_ENABLED (0)

...

SomeFunction()
{
    int someVariable = 5;

#if(DEBUG_ENABLED)
    printf("Debugging: someVariable == %d", someVariable);
#endif
}

บางทีมชอบสิ่งต่อไปนี้:

// #define DEBUG_ENABLED

...

SomeFunction()
{
    int someVariable = 5;

#ifdef DEBUG_ENABLED
    printf("Debugging: someVariable == %d", someVariable);
#endif
}

... วิธีใดที่เหมาะกับคุณมากกว่าและเพราะเหตุใด ความรู้สึกของฉันคืออย่างแรกปลอดภัยกว่าเพราะมีบางสิ่งที่กำหนดไว้เสมอและไม่มีอันตรายที่จะไปทำลายนิยามอื่นที่อื่นได้


หมายเหตุ:ด้วย#ifคุณสามารถใช้#elifในลักษณะที่สอดคล้องกันได้ซึ่งแตกต่างจาก#ifdefไฟล์. ดังนั้นแทนที่จะใช้เพียง#define BLAHใช้#define BLAH 1กับ#if BLAHฯลฯ ...
แอนดรูว์

คำตอบ:


82

#ifdefแน่นอนว่าปฏิกิริยาเริ่มต้นของฉันคือแต่ฉันคิดว่า#ifจริงๆแล้วมีข้อดีที่สำคัญสำหรับสิ่งนี้ - นี่คือเหตุผล:

ขั้นแรกคุณสามารถใช้DEBUG_ENABLEDในการทดสอบตัวประมวลผลก่อนและคอมไพล์ ตัวอย่าง - บ่อยครั้งฉันต้องการการหมดเวลานานขึ้นเมื่อเปิดใช้งานการดีบักดังนั้นการใช้#ifฉันสามารถเขียนสิ่งนี้ได้

  DoSomethingSlowWithTimeout(DEBUG_ENABLED? 5000 : 1000);

... แทน ...

#ifdef DEBUG_MODE
  DoSomethingSlowWithTimeout(5000);
#else
  DoSomethingSlowWithTimeout(1000);
#endif

ประการที่สองคุณอยู่ในตำแหน่งที่ดีขึ้นหากคุณต้องการย้ายจาก#defineค่าคงที่ไปเป็นค่าคงที่ทั่วโลก #defines มักจะขมวดคิ้วโดยโปรแกรมเมอร์ C ++ ส่วนใหญ่

และประการที่สามคุณบอกว่าคุณมีความแตกแยกในทีม ฉันเดาว่านี่หมายความว่าสมาชิกหลายคนได้ใช้แนวทางที่แตกต่างกันไปแล้วและคุณจำเป็นต้องสร้างมาตรฐาน การพิจารณาว่า#ifเป็นตัวเลือกที่ต้องการหมายความว่าโค้ดที่ใช้#ifdefจะคอมไพล์ - และรัน - แม้ว่าDEBUG_ENABLEDจะเป็นเท็จก็ตาม และง่ายกว่ามากในการติดตามและลบเอาต์พุตการดีบักที่สร้างขึ้นเมื่อไม่ควรจะเป็นในทางกลับกัน

โอ้และจุดอ่านเล็กน้อย คุณควรจะสามารถใช้ true / false แทนที่จะเป็น 0/1 ในของคุณ#defineและเนื่องจากค่าเป็นโทเค็นคำศัพท์เดียวจึงเป็นครั้งเดียวที่คุณไม่จำเป็นต้องมีวงเล็บล้อมรอบ

#define DEBUG_ENABLED true

แทน

#define DEBUG_ENABLED (1)

อาจไม่สามารถใช้ค่าคงที่เพื่อเปิด / ปิดการดีบักได้ดังนั้นการทริกเกอร์ #ifdef ด้วย #define ถึง 0 จึงไม่เป็นอันตราย สำหรับจริง / เท็จสิ่งเหล่านี้ถูกเพิ่มใน C99 และไม่มีอยู่ใน C89 / C90
Michael Carman

Micheal: เขา / เธอต่อต้านการใช้ #ifdef?!
Jon Cage

7
ใช่ปัญหาหนึ่ง#ifdefคือการทำงานกับสิ่งที่ไม่ได้กำหนดไว้ ไม่ว่าพวกเขาจะไม่ได้กำหนดโดยเจตนาหรือเพราะการพิมพ์ผิดหรือคุณมีอะไร
bames53

6
นอกจากคำตอบของคุณไม่ถูกต้อง #if DEBUG_ENBALEDไม่ใช่ข้อผิดพลาดที่ตรวจพบโดยพรีโปรเซสเซอร์ หากDEBUG_ENBALEDไม่ได้กำหนดไว้จะขยายเป็นโทเค็น0ใน#ifคำสั่ง
R .. GitHub STOP HELPING ICE

6
@R .. ในคอมไพเลอร์จำนวนมากคุณสามารถเปิดใช้คำเตือนสำหรับ "#if DEBUG_ENABLED" เมื่อไม่ได้กำหนด DEBUG_ENABLED ใน GCC ให้ใช้ "-Wundef" ใน Microsoft Visual Studio ให้ใช้ "/ w14668" เพื่อเปิด C4668 เป็นการเตือนระดับ 1
จะ

56

ทั้งคู่น่าเกลียด ให้ทำสิ่งนี้แทน:

#ifdef DEBUG
#define D(x) do { x } while(0)
#else
#define D(x) do { } while(0)
#endif

D();จากนั้นเมื่อใดก็ตามที่คุณจำเป็นต้องใช้รหัสแก้ปัญหาใส่ไว้ใน #ifdefและโปรแกรมของคุณจะไม่ถูกปนเปื้อนด้วยเขาวงกตที่น่าเกลียดของ


6
@MatthieuM. อันที่จริงฉันคิดว่าเวอร์ชั่นดั้งเดิมนั้นดี อัฒภาคจะถูกตีความว่าเป็นข้อความว่าง อย่างไรก็ตามการลืมอัฒภาคอาจทำให้เป็นอันตรายได้
Casey Kuball


20

เรามีปัญหาเดียวกันนี้ในหลายไฟล์และมักจะมีปัญหากับคนที่ลืมใส่ไฟล์ "แฟล็กฟีเจอร์" (ด้วย codebase> 41,000 ไฟล์จึงทำได้ง่าย)

หากคุณมี feature.h:

#ifndef FEATURE_H
#define FEATURE_H

// turn on cool new feature
#define COOL_FEATURE 1

#endif // FEATURE_H

แต่แล้วคุณลืมรวมไฟล์ส่วนหัวใน file.cpp:

#if COOL_FEATURE
    // definitely awesome stuff here...
#endif

จากนั้นคุณมีปัญหาคอมไพลเลอร์ตีความว่า COOL_FEATURE ไม่ได้กำหนดเป็น "เท็จ" ในกรณีนี้และไม่สามารถรวมโค้ดได้ ใช่ gcc รองรับแฟล็กที่ทำให้เกิดข้อผิดพลาดสำหรับมาโครที่ไม่ได้กำหนด ... แต่โค้ดของบุคคลที่สามส่วนใหญ่กำหนดหรือไม่ได้กำหนดคุณสมบัติดังนั้นนี่จะไม่ใช่แบบพกพา

เราได้ใช้วิธีการแก้ไขแบบพกพาสำหรับกรณีนี้รวมทั้งการทดสอบสถานะของคุณลักษณะ: ฟังก์ชันมาโคร

หากคุณเปลี่ยนคุณสมบัติข้างต้น h เป็น:

#ifndef FEATURE_H
#define FEATURE_H

// turn on cool new feature
#define COOL_FEATURE() 1

#endif // FEATURE_H

แต่แล้วคุณก็ลืมที่จะรวมไฟล์ส่วนหัวใน file.cpp อีกครั้ง:

#if COOL_FEATURE()
    // definitely awseome stuff here...
#endif

ตัวประมวลผลล่วงหน้าอาจผิดพลาดเนื่องจากการใช้มาโครฟังก์ชันที่ไม่ได้กำหนด


17

สำหรับวัตถุประสงค์ในการดำเนินการคอมไพล์ตามเงื่อนไข #if และ #ifdef นั้นเกือบจะเหมือนกัน แต่ก็ไม่มาก หากการคอมไพล์ตามเงื่อนไขของคุณขึ้นอยู่กับสองสัญลักษณ์ #ifdef ก็จะไม่ทำงานเช่นกัน ตัวอย่างเช่นสมมติว่าคุณมีสัญลักษณ์การคอมไพล์ตามเงื่อนไขสองแบบคือ PRO_VERSION และ TRIAL_VERSION คุณอาจมีสิ่งนี้:

#if defined(PRO_VERSION) && !defined(TRIAL_VERSION)
...
#else
...
#endif

การใช้ #ifdef ข้างต้นมีความซับซ้อนมากขึ้นโดยเฉพาะการทำให้ส่วน #else ทำงาน

ฉันทำงานกับโค้ดที่ใช้การคอมไพล์ตามเงื่อนไขอย่างกว้างขวางและเรามี #if & #ifdef ผสมกัน เรามักจะใช้ # ifdef / # ifndef สำหรับกรณีธรรมดาและ #if เมื่อใดก็ตามที่มีการประเมินสัญลักษณ์สองตัวขึ้นไป


1
ใน#if definedสิ่งที่เป็นdefinedมันเป็นคำที่สำคัญหรือ?
nmxprime

15

ฉันคิดว่ามันเป็นคำถามเกี่ยวกับสไตล์โดยสิ้นเชิง ทั้งสองไม่มีข้อได้เปรียบที่ชัดเจนเหนือสิ่งอื่นใด

ความสม่ำเสมอมีความสำคัญมากกว่าทางเลือกใดทางเลือกหนึ่งดังนั้นฉันขอแนะนำให้คุณทำงานร่วมกับทีมของคุณและเลือกสไตล์เดียวและยึดติดกับมัน


8

ฉันชอบ:

#if defined(DEBUG_ENABLED)

เนื่องจากมันช่วยให้สร้างโค้ดที่มองหาเงื่อนไขตรงข้ามได้ง่ายขึ้นมาก:

#if !defined(DEBUG_ENABLED)

เทียบกับ

#ifndef(DEBUG_ENABLED)

8
โดยส่วนตัวฉันคิดว่ามันง่ายกว่าที่จะพลาดเครื่องหมายตกใจเล็ก ๆ !
Jon Cage

6
ด้วยการเน้นไวยากรณ์? :) ในการเน้นไวยากรณ์ "n" ใน "ifndef" จะมองเห็นได้ยากกว่ามากเนื่องจากเป็นสีเดียวกันทั้งหมด
Jim Buck

โอเคฉันหมายถึง #ifndef นั้นง่ายกว่าที่จะระบุ #if! กำหนดไว้เมื่อคุณเปรียบเทียบกับ #if ที่กำหนด .. แต่เมื่อกำหนด #if ทั้งหมด / # if! กำหนดเทียบกับ # ifdef / # ifndef ทั้งสองอย่างก็อ่านพลาดไม่แพ้กัน!
Jon Cage

@JonCage ฉันรู้ว่ามันเป็นเวลาไม่กี่ปีแล้วที่ความคิดเห็นนี้ แต่ฉันอยากจะชี้ให้เห็นว่าคุณสามารถเขียนได้#if ! definedเพื่อให้!โดดเด่นและยากที่จะพลาด
Pharap

@Pharap - ดูเหมือนว่าจะมีการปรับปรุงอย่างแน่นอน :)
Jon Cage

7

มันเป็นเรื่องของสไตล์ แต่ฉันขอแนะนำวิธีที่กระชับกว่านี้:

#ifdef USE_DEBUG
#define debug_print printf
#else
#define debug_print
#endif

debug_print("i=%d\n", i);

คุณทำสิ่งนี้เพียงครั้งเดียวจากนั้นใช้ debug_print () เพื่อพิมพ์หรือไม่ทำอะไรเลย (ใช่สิ่งนี้จะรวบรวมในทั้งสองกรณี) ด้วยวิธีนี้รหัสของคุณจะไม่อ่านไม่ออกด้วยคำสั่งพรีโปรเซสเซอร์

หากคุณได้รับคำเตือน "นิพจน์ไม่มีผล" และต้องการกำจัดออกไปนี่เป็นทางเลือกอื่น:

void dummy(const char*, ...)
{}

#ifdef USE_DEBUG
#define debug_print printf
#else
#define debug_print dummy
#endif

debug_print("i=%d\n", i);

3
บางทีมาโครการพิมพ์อาจไม่ใช่ตัวอย่างที่ดีที่สุดหลังจากนั้นเราได้ทำสิ่งนี้แล้วในโค้ดเบสของเราสำหรับโค้ดดีบักมาตรฐานเพิ่มเติม เราใช้บิต #if / #ifdefined สำหรับพื้นที่ที่คุณอาจต้องการเปิดการดีบักพิเศษ ..
Jon Cage

5

#ifให้คุณมีตัวเลือกในการตั้งค่าเป็น 0 เพื่อปิดฟังก์ชันการทำงานในขณะที่ยังตรวจพบว่ามีสวิตช์อยู่
โดยส่วนตัวแล้วฉันมัก#define DEBUG 1จะจับมันได้ด้วย #if หรือ #ifdef


1
สิ่งนี้ล้มเหลวเนื่องจาก #define DEBUG = 0 จะไม่ทำงาน #if แต่จะเรียกใช้ #ifdef
tloach

1
นั่นคือประเด็นฉันสามารถลบ DEBUG ได้ทั้งหมดหรือเพียงแค่ตั้งค่าเป็น 0 เพื่อปิดใช้งาน
Martin Beckett

#define DEBUG 1มันควรจะเป็น ไม่#define DEBUG=1
Keshava GN

4

#if และ # กำหนด MY_MACRO (0)

การใช้ #if หมายความว่าคุณได้สร้างมาโคร "กำหนด" นั่นคือสิ่งที่จะค้นหาในโค้ดที่จะถูกแทนที่ด้วย "(0)" นี่คือ "มาโครนรก" ที่ฉันไม่อยากเห็นใน C ++ เพราะมันทำให้โค้ดเสียหายด้วยการแก้ไขโค้ดที่อาจเกิดขึ้น

ตัวอย่างเช่น:

#define MY_MACRO (0)

int doSomething(int p_iValue)
{
   return p_iValue + 1 ;
}

int main(int argc, char **argv)
{
   int MY_MACRO = 25 ;
   doSomething(MY_MACRO) ;

   return 0;
}

ให้ข้อผิดพลาดต่อไปนี้ใน g ++:

main.cpp|408|error: lvalue required as left operand of assignment|
||=== Build finished: 1 errors, 0 warnings ===|

เพียงหนึ่งเดียวข้อผิดพลาด

ซึ่งหมายความว่าแมโครของคุณโต้ตอบกับรหัส C ++ ของคุณสำเร็จ: การเรียกใช้ฟังก์ชันสำเร็จ ในกรณีง่ายๆนี้มันน่าขบขัน แต่ประสบการณ์ของฉันเองกับการเล่นมาโครอย่างเงียบ ๆ ด้วยรหัสของฉันนั้นไม่ได้เต็มไปด้วยความสุขและความสมบูรณ์ดังนั้น ...

#ifdef และ #define MY_MACRO

การใช้ #ifdef หมายความว่าคุณ "กำหนด" บางอย่าง ไม่ใช่ว่าคุณให้ค่ามัน มันยังคงก่อมลพิษ แต่อย่างน้อยมันจะถูก "แทนที่ด้วยอะไร" และโค้ด C ++ จะไม่ถูกมองว่าเป็นคำสั่งรหัสที่ล้าสมัย รหัสเดียวกันด้านบนด้วยการกำหนดง่ายๆมัน:

#define MY_MACRO

int doSomething(int p_iValue)
{
   return p_iValue + 1 ;
}

int main(int argc, char **argv)
{
   int MY_MACRO = 25 ;
   doSomething(MY_MACRO) ;

   return 0;
}

ให้คำเตือนต่อไปนี้:

main.cpp||In function int main(int, char**)’:|
main.cpp|406|error: expected unqualified-id before ‘=’ token|
main.cpp|399|error: too few arguments to function int doSomething(int)’|
main.cpp|407|error: at this point in file|
||=== Build finished: 3 errors, 0 warnings ===|

ดังนั้น...

สรุป

ฉันอยากใช้ชีวิตโดยไม่มีมาโครในโค้ดของฉัน แต่ด้วยเหตุผลหลายประการ (การกำหนดส่วนป้องกันส่วนหัวหรือมาโครการแก้ไขข้อบกพร่อง) ฉันทำไม่ได้

แต่อย่างน้อยฉันต้องการให้พวกเขาโต้ตอบน้อยที่สุดเท่าที่จะเป็นไปได้ด้วยรหัส C ++ ที่ถูกต้องของฉัน ซึ่งหมายถึงการใช้ #define โดยไม่มีค่าโดยใช้ #ifdef และ #ifndef (หรือแม้กระทั่ง #if ที่กำหนดตามที่ Jim Buck แนะนำ) และที่สำคัญที่สุดคือการตั้งชื่อให้ยาวมากและคนต่างด้าวจะไม่มีใครในความคิดที่ถูกต้องของเขา / เธอใช้ "โดยบังเอิญ" และจะไม่มีผลต่อรหัส C ++ ที่ถูกต้องตามกฎหมาย

โพสต์ Scriptum

ตอนนี้ฉันกำลังอ่านโพสต์ของฉันอีกครั้งฉันสงสัยว่าฉันไม่ควรพยายามหาค่าบางอย่างที่ไม่เคยถูกต้อง C ++ เพื่อเพิ่มในการกำหนดของฉัน สิ่งที่ต้องการ

#define MY_MACRO @@@@@@@@@@@@@@@@@@

ที่สามารถใช้กับ #ifdef และ #ifndef ได้ แต่อย่าให้โค้ดคอมไพล์หากใช้ภายในฟังก์ชัน ... ฉันลองสิ่งนี้สำเร็จบน g ++ และทำให้เกิดข้อผิดพลาด:

main.cpp|410|error: stray ‘@’ in program|

น่าสนใจ. :-)


ฉันยอมรับว่ามาโครอาจเป็นอันตรายได้ แต่ตัวอย่างแรกนั้นค่อนข้างชัดเจนในการดีบักและแน่นอนว่ามันมีข้อผิดพลาดเพียงข้อเดียว ทำไมคุณถึงคาดหวังมากขึ้น? ฉันเห็นข้อผิดพลาดที่น่ากลัวกว่ามากอันเป็นผลมาจากมาโคร ...
Jon Cage

เป็นความจริงความแตกต่างระหว่างวิธีแก้ปัญหาหนึ่งกับอีกวิธีหนึ่งแทบจะไม่สำคัญ แต่ในกรณีนี้ในขณะที่เรากำลังพูดถึงรูปแบบการเข้ารหัสสองแบบที่แข่งขันกันแม้แต่เรื่องเล็กน้อยก็ไม่สามารถละเลยได้เพราะหลังจากนั้นสิ่งที่เหลืออยู่ก็คือรสนิยมส่วนตัว (และ ณ จุดนั้นฉันเชื่อว่ามันไม่ควรทำให้เป็นมาตรฐาน )
paercebal

4

นั่นไม่ใช่เรื่องของสไตล์เลย นอกจากนี้คำถามยังไม่ถูกต้อง คุณไม่สามารถเปรียบเทียบคำสั่งพรีโปรเซสเซอร์เหล่านี้ในแง่ที่ดีกว่าหรือปลอดภัยกว่า

#ifdef macro

หมายถึง "ถ้ากำหนดมาโคร" หรือ "ถ้ามีมาโคร" ค่าของมาโครไม่สำคัญที่นี่ จะเป็นอย่างไรก็ได้

#if macro

ถ้าเปรียบเทียบกับค่าเสมอ ในตัวอย่างข้างต้นเป็นการเปรียบเทียบโดยนัยมาตรฐาน:

#if macro !=0

ตัวอย่างการใช้ #if

#if CFLAG_EDITION == 0
    return EDITION_FREE;
#elif CFLAG_EDITION == 1
    return EDITION_BASIC;
#else
    return EDITION_PRO;
#endif

ตอนนี้คุณสามารถใส่คำจำกัดความของ CFLAG_EDITION ในโค้ดของคุณได้

#define CFLAG_EDITION 1 

หรือคุณสามารถตั้งค่ามาโครเป็นแฟล็กคอมไพเลอร์ นอกจากนี้ยังดูที่นี่


2

ครั้งแรกดูเหมือนชัดเจนสำหรับฉัน ดูเหมือนเป็นธรรมชาติมากขึ้นทำให้เป็นแฟล็กเมื่อเทียบกับกำหนด / ไม่ได้กำหนดไว้


2

ทั้งสองเทียบเท่ากันทุกประการ ในการใช้สำนวน #ifdef จะใช้เพื่อตรวจสอบความถูกต้อง (และสิ่งที่ฉันจะใช้ในตัวอย่างของคุณ) ในขณะที่ #if ใช้ในนิพจน์ที่ซับซ้อนกว่าเช่น #if กำหนด (A) &&! กำหนด (B)


1
OP ไม่ได้ถามว่าระหว่าง "#ifdef" กับ "#if กำหนดไว้แบบไหนดีกว่า" แต่จะอยู่ระหว่าง "# ifdef / # ถ้ากำหนด" กับ "#if"
ก้าน

1

OT เล็กน้อย แต่การเปิด / ปิดการบันทึกด้วยตัวประมวลผลล่วงหน้านั้นเหมาะสมที่สุดใน C ++ มีเครื่องมือบันทึกที่ดีเช่นlog4cxxของ Apache ซึ่งเป็นโอเพ่นซอร์สและไม่ จำกัด วิธีการเผยแพร่แอปพลิเคชันของคุณ นอกจากนี้ยังช่วยให้คุณสามารถเปลี่ยนระดับการบันทึกโดยไม่ต้องคอมไพล์ใหม่มีค่าใช้จ่ายที่ต่ำมากหากคุณปิดการบันทึกและให้โอกาสคุณในการปิดการบันทึกอย่างสมบูรณ์ในการใช้งานจริง


1
ฉันเห็นด้วยและเราก็ทำเช่นนั้นในโค้ดของเราฉันแค่อยากได้ตัวอย่างของสิ่งที่คุณอาจใช้ #if เป็นต้นสำหรับ
Jon Cage

1

ผมเคยใช้ #ifdefแต่เมื่อฉันเปลี่ยนไปใช้ Doxygen สำหรับเอกสารฉันพบว่ามาโครที่แสดงความคิดเห็นไม่สามารถจัดทำเป็นเอกสารได้ (หรืออย่างน้อย Doxygen ก็สร้างคำเตือน) ซึ่งหมายความว่าฉันไม่สามารถบันทึกมาโครการสลับคุณลักษณะที่ไม่ได้เปิดใช้งานอยู่ในขณะนี้

แม้ว่าจะเป็นไปได้ที่จะกำหนดมาโครสำหรับ Doxygen เท่านั้น แต่หมายความว่ามาโครในส่วนที่ไม่ใช้งานของโค้ดจะได้รับการจัดทำเป็นเอกสารด้วย โดยส่วนตัวฉันต้องการแสดงสวิตช์คุณสมบัติและทำเอกสารเฉพาะสิ่งที่เลือกไว้ในขณะนี้ นอกจากนี้ยังทำให้โค้ดค่อนข้างยุ่งหากมีมาโครจำนวนมากที่ต้องกำหนดเมื่อ Doxygen ประมวลผลไฟล์เท่านั้น

#ifดังนั้นในกรณีนี้มันจะดีกว่าเสมอกำหนดแมโครและการใช้งาน


0

ฉันใช้แฟล็ก #ifdef และคอมไพเลอร์เพื่อกำหนดเสมอ ...


มีเหตุผลใดเป็นพิเศษ (จากความอยากรู้อยากเห็น)?
Jon Cage

2
พูดตามตรงฉันไม่เคยคิดถึงเรื่องนี้เลย - เพียงแค่สถานที่ที่ฉันเคยทำงาน มันให้ข้อได้เปรียบที่แทนที่จะทำการเปลี่ยนแปลงโค้ดสำหรับบิลด์การผลิตสิ่งที่คุณต้องทำคือ 'ทำการดีบัก' สำหรับการดีบักหรือ 'ทำการผลิต' เป็นประจำ
tloach

0

หรือคุณสามารถประกาศค่าคงที่ส่วนกลางและใช้ C ++ if แทนตัวประมวลผลก่อน #if คอมไพเลอร์ควรปรับแต่งกิ่งก้านที่ไม่ได้ใช้ให้เหมาะสมสำหรับคุณและโค้ดของคุณจะสะอาดขึ้น

นี่คือสิ่งที่C ++ Gotchasโดย Stephen C.Dewhurst กล่าวเกี่ยวกับการใช้ # if's


1
นั่นเป็นวิธีแก้ปัญหาที่ไม่ดี แต่มีปัญหาดังต่อไปนี้: 1. ใช้งานได้เฉพาะในฟังก์ชันคุณไม่สามารถลบตัวแปรคลาสที่ไม่จำเป็นได้ ฯลฯ 2. คอมไพเลอร์อาจส่งคำเตือนเกี่ยวกับโค้ดที่ไม่สามารถเข้าถึงได้ 3. โค้ดใน if ยังต้องคอมไพล์ซึ่งหมายความว่า คุณต้องกำหนดฟังก์ชันการดีบักไว้ทั้งหมดเป็นต้น
Don Neufeld

ประการแรกคำถามคือเฉพาะเกี่ยวกับการดีบัก printfs ดังนั้นตัวแปรคลาสที่ไม่จำเป็นจึงไม่ใช่ปัญหาที่นี่ ประการที่สองเนื่องจากความสามารถของคอมไพเลอร์สมัยใหม่คุณควรใช้ #ifdefs ให้น้อยที่สุด ในกรณีส่วนใหญ่คุณสามารถใช้การกำหนดค่าการสร้างหรือความเชี่ยวชาญพิเศษของเทมเพลตแทนได้
Dima

0

มีความแตกต่างในกรณีของวิธีต่างๆในการระบุการกำหนดเงื่อนไขให้กับไดรเวอร์:

diff <( echo | g++ -DA= -dM -E - ) <( echo | g++ -DA -dM -E - )

เอาต์พุต:

344c344
< #define A 
---
> #define A 1

ซึ่งหมายความว่า-DAเป็นคำพ้องความหมาย-DA=1และหากละเว้นค่าอาจทำให้เกิดปัญหาในกรณี#if Aการใช้งาน


0

ฉันชอบ#define DEBUG_ENABLED (0)เวลาที่คุณอาจต้องการดีบักหลายระดับ ตัวอย่างเช่น:

#define DEBUG_RELEASE (0)
#define DEBUG_ERROR (1)
#define DEBUG_WARN (2)
#define DEBUG_MEM (3)
#ifndef DEBUG_LEVEL
#define DEBUG_LEVEL (DEBUG_RELEASE)
#endif
//...

//now not only
#if (DEBUG_LEVEL)
//...
#endif

//but also
#if (DEBUG_LEVEL >= DEBUG_MEM)
LOG("malloc'd %d bytes at %s:%d\n", size, __FILE__, __LINE__);
#endif

ทำให้การดีบักการรั่วไหลของหน่วยความจำง่ายขึ้นโดยไม่ต้องมีบรรทัดบันทึกทั้งหมดในการดีบักสิ่งอื่น ๆ

นอกจากนี้การ#ifndefกำหนดรอบ ๆ ยังทำให้ง่ายต่อการเลือกระดับการดีบักที่บรรทัดคำสั่ง:

make -DDEBUG_LEVEL=2
cmake -DDEBUG_LEVEL=2
etc

ถ้าไม่ใช่สำหรับสิ่งนี้ฉันจะให้ประโยชน์#ifdefเพราะแฟล็กคอมไพเลอร์ / make จะถูกแทนที่โดยแฟล็กในไฟล์ คุณจึงไม่ต้องกังวลกับการเปลี่ยนกลับส่วนหัวก่อนทำการคอมมิต

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