_DEBUG เทียบกับ NDEBUG


142

ควรใช้ตัวประมวลผลล่วงหน้าชุดใดเพื่อระบุส่วนการดีบักของรหัส

ใช้#ifdef _DEBUGหรือ#ifndef NDEBUGหรือมีวิธีที่ดีกว่าที่จะทำเช่น#define MY_DEBUG?

ฉันคิดว่า_DEBUGเป็น Visual Studio เฉพาะมาตรฐาน NDEBUG หรือไม่

คำตอบ:


113

Visual Studio กำหนด_DEBUGเมื่อคุณระบุ/MTdหรือ/MDdตัวเลือกNDEBUGปิดการใช้งานการยืนยันมาตรฐาน C ใช้พวกเขาในเวลาที่เหมาะสมเช่น_DEBUGถ้าคุณต้องการรหัสแก้จุดบกพร่องของคุณเพื่อให้สอดคล้องกับเทคนิค MS CRT แก้จุดบกพร่องและถ้าคุณต้องการเพื่อให้สอดคล้องกับNDEBUGassert()

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


19
+1 โดยเฉพาะอย่างยิ่ง NDEBUG ได้รับอนุญาตให้เป็น # undef'd และ # define'd ภายใน TU เดียว (และรวม <assert.h> อีกครั้งเปลี่ยนแมโครยืนยันตาม) เนื่องจากสิ่งนี้แตกต่างจากที่คาดไว้ / ต้องการเป็นเรื่องปกติที่จะใช้แมโครอื่นเพื่อควบคุมการตั้งค่าสถานะการดีบักแบบ "คอมไพล์" ตามคำตอบนี้

1
เห็นได้ชัดว่ามันเป็นคอมไพเลอร์เองที่กำหนดมาโครเหล่านี้ไม่ใช่ Visual Studio (the IDE) ขอบคุณมากสำหรับคำตอบนี้!
Niklas R

NDEBUG ไม่ได้ถูกกำหนดเมื่อใช้แม่แบบแอปพลิเคชันจาก Windows Driver Kit 8.1 ในกรณีนี้คุณอาจต้องพึ่งพา _DEBUG
navossoc

53

เป็นมาตรฐาน NDEBUG หรือไม่

ใช่มันเป็นแมโครมาตรฐานที่มีความหมาย "Not Debug" สำหรับ C89, C99, C ++ 98, C ++ 2003, C ++ 2011, C ++ 2014 ไม่มี_DEBUGมาโครในมาตรฐาน

มาตรฐาน C ++ 2003 ส่งผู้อ่านไปที่ "หน้า 326" ที่ "17.4.2.1 ส่วนหัว" ถึงมาตรฐาน C

NDEBUG นั้นคล้ายกันกับนี่เหมือนกับไลบรารี C มาตรฐาน

ใน C89 (โปรแกรมเมอร์ C เรียกว่ามาตรฐานนี้เป็นมาตรฐาน C) ในส่วน "4.2 DIAGNOSTICS"

http://port70.net/~nsz/c/c89/c89-draft.html

ถ้า NDEBUG ถูกกำหนดให้เป็นชื่อแมโครที่จุดในไฟล์ต้นฉบับที่มีอยู่แมโคร assert จะถูกกำหนดอย่างง่าย ๆ ดังนี้

     #define assert(ignore) ((void)0)

หากดูความหมายของ_DEBUGมาโครใน Visual Studio https://msdn.microsoft.com/en-us/library/b0084kay.aspx จะเห็นได้ว่ามาโครนี้ถูกกำหนดโดยอัตโนมัติโดยเวอร์ชันไลบรารีรันไทม์ภาษาของคุณ


50

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

การพึ่งพาบางสิ่งเช่น_DEBUGนั้นก็คือการพึ่งพารายละเอียดการใช้งานของคอมไพเลอร์และการใช้งานไลบรารี คอมไพเลอร์อื่น ๆ อาจจะหรืออาจจะไม่เลือกแบบแผนเดียวกัน

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

ด้วยตัวเลือกใด ๆ เหล่านี้หากคุณใช้รหัสของบุคคลที่สามเป็นส่วนหนึ่งของโครงการของคุณคุณจะต้องทราบถึงข้อตกลงที่ใช้


1
#if !defined(NDEBUG)<- @HostileFork นั่นไม่ใช่สิ่งที่คุณหมายถึงเหรอ? #ifไม่ใช่#ifdefเหรอ
Bob Stein

1
ความคิดเห็นเดิมแก้ไขผ่าน @BobStein: "สิ่งที่ฉันได้นำตัวไปทำเพื่อ (เล็กน้อย) ลดการอ่าน 'speedbump' คือว่าเมื่อพูดคุยเกี่ยวกับการใช้งานในสภาพที่ไม่มีการแก้ปัญหา#ifdef NDEBUG... #if !defined(NDEBUG)แต่แล้วเรียกความสนใจเป็นพิเศษกับตรรกะเชิงลบด้วยไม่งั้นมันก็ยากที่จะจับตัว n ใน#ifndef NDEBUG"
HostileFork บอกว่าอย่าไว้ใจ SE

17

แมโครNDEBUGควบคุมว่าassert()ข้อความสั่งทำงานหรือไม่

ในมุมมองของฉันที่แยกจากการดีบักอื่น ๆ - ดังนั้นฉันใช้สิ่งอื่นที่ไม่ใช่ NDEBUGการควบคุมข้อมูลการดีบักในโปรแกรม สิ่งที่ฉันใช้แตกต่างกันไปขึ้นอยู่กับกรอบที่ฉันทำงานด้วย ระบบที่แตกต่างกันมีแมโครที่เปิดใช้งานที่แตกต่างกันและฉันใช้สิ่งที่เหมาะสม

หากไม่มีกรอบฉันจะใช้ชื่อโดยไม่มีขีดเส้นใต้ ผู้ที่มีแนวโน้มที่จะถูกสงวนไว้ที่ 'การใช้งาน' และฉันพยายามหลีกเลี่ยงปัญหาเกี่ยวกับการชนชื่อ - สองเท่าดังนั้นเมื่อชื่อเป็นมาโคร


คุณช่วยอธิบายได้ไหมว่าทำไมคุณถึงคิดว่าแตกต่างจากการดีบักประเภทอื่น ในสถานการณ์ใดที่คุณต้องการและไม่อื่น
Adrian McCarthy

4
ฉันยังคงยืนยันการใช้งานแม้ในขณะที่ฉันไม่ได้รวบรวมการดีบักหรือติดตามสิ่งอำนวยความสะดวกอื่น ๆ ลงในรหัส ยืนยันระบุสถานการณ์ที่เป็นไปไม่ได้ การติดตามและการดีบักทั่วไป IMO แยกต่างหากจากนั้น
Jonathan Leffler

2
@AdrianMcCarthy: หากคุณเปิดใช้งานการดีบักทั้งหมดอาจทำให้โปรแกรมเรียกใช้ INCREDIBLY ช้า ดังนั้นจึงเป็นเรื่องธรรมดาที่จะจัดหมวดหมู่ประเภทการดีบักและอนุญาตให้ผู้ใช้เปิด / ปิดการใช้งานแยกต่างหาก MSVC มีสองหรือสามอย่างที่พวกเขาใช้เพื่อเปิด / ปิดการดีบักต่างๆสำหรับไลบรารีมาตรฐานเช่น std :: vector
Mooing Duck

@MooingDuck: เห็นด้วย แต่แยกแยะระหว่าง 'การดีบักที่มีอยู่และเปิดใช้งาน' และ 'การดีบักพร้อมใช้งาน แต่ปิดใช้งาน' และ 'การดีบักไม่พร้อมใช้งาน' การตัดสินใจที่พร้อมใช้งาน / ไม่พร้อมใช้งานเป็นปัญหาเวลาการคอมไพล์ (ในรหัส C หรือ C ++), และเปิดใช้งาน / ปิดใช้งานนั้นเป็นการตัดสินใจรันไทม์เมื่อการดีบักพร้อมใช้งาน เฉพาะระบบการแก้ไขข้อบกพร่องที่หยาบที่สุดเท่านั้นที่ทำงานกับโหมด 'พร้อมใช้งานหมายความว่าเปิดใช้งาน' (ที่กล่าวว่าน้ำมันดิบจะมีประสิทธิภาพและมีจำนวนมากของน้ำมันดิบ - แต่มีประสิทธิภาพเพียงพอ - ระบบดีบั๊กอยู่ในป่า!)
Jonathan Leffler

2
@MooingDuck: ใช่รหัสการแก้ไขข้อบกพร่องบางอย่างอาจเปลี่ยนแปลงช้า ในกรณีดังกล่าวคุณอาจต้องการวิธีที่จะควบคุมว่าโค้ดที่ช้าทำงานโดยอิสระจากการตรวจสอบเล็กน้อยหรือไม่ แต่นั่นไม่เหมือนกับการยืนยันในหมวดหมู่หนึ่งและ#ifรหัสที่ควบคุมได้ในอีกประเภทหนึ่ง assert(huge_object.IsValid());อาจช้าในขณะที่assert(ptr != nullptr);อาจไม่ใช่ ฉันเห็นด้วยกับโจนาธานว่าการบันทึกและการติดตามควรจะแตกต่างจากการยืนยันอย่างน้อยในโครงการขนาดใหญ่ แต่ฉันไม่คิดว่าการบันทึกหรือการสืบค้นกลับเป็นรหัสดีบักซึ่งเป็นสาเหตุที่ฉันขอคำชี้แจง
Adrian McCarthy

6

มีความสอดคล้องและมันไม่สำคัญว่าจะเป็นที่หนึ่ง นอกจากนี้หากมีเหตุผลบางอย่างที่คุณต้องทำงานร่วมกับโปรแกรมหรือเครื่องมืออื่นโดยใช้ตัวระบุ DEBUG บางตัวมันก็สามารถทำได้

#ifdef THEIRDEBUG
#define MYDEBUG
#endif //and vice-versa

4

น่าเสียดายที่DEBUGมีการใช้งานมากเกินไป ตัวอย่างเช่นแนะนำให้สร้างและบันทึกไฟล์ pdb สำหรับการสร้าง RELEASE เสมอ ซึ่งหมายถึงหนึ่งใน-Zxแฟล็กและ-DEBUGตัวเลือกลิงก์ ในขณะที่_DEBUGเกี่ยวข้องกับการแก้ปัญหารุ่นพิเศษของไลบรารีรันไทม์เช่นโทรไปและmalloc freeจากนั้นNDEBUGจะปิดใช้งานการยืนยัน

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