_DEBUG so với NDEBUG


142

Nên sử dụng định nghĩa tiền xử lý nào để xác định các phần gỡ lỗi của mã?

Sử dụng #ifdef _DEBUGhoặc #ifndef NDEBUGcó một cách tốt hơn để làm điều đó, ví dụ #define MY_DEBUG?

Tôi nghĩ _DEBUGlà Visual Studio cụ thể, là tiêu chuẩn NDEBUG?

Câu trả lời:


113

Visual Studio xác định _DEBUGkhi bạn chỉ định /MTdhoặc /MDdtùy chọn, NDEBUGvô hiệu hóa các xác nhận C-tiêu chuẩn. Sử dụng chúng khi thích hợp, tức là _DEBUGnếu bạn muốn mã gỡ lỗi của mình phù hợp với các kỹ thuật gỡ lỗi MS CRTNDEBUGnếu bạn muốn phù hợp với assert().

Nếu bạn xác định các macro gỡ lỗi của riêng mình (và bạn không hack trình biên dịch hoặc thời gian chạy C), hãy tránh bắt đầu các tên có dấu gạch dưới, vì chúng được bảo lưu.


19
+1. Cụ thể, NDEBUG được phép là # undef'd và # xác định trong một TU (và bao gồm <assert.h> thay đổi macro xác nhận tương ứng). Vì điều này khác với mong đợi / mong muốn, nên thường sử dụng một macro khác để điều khiển cờ gỡ lỗi "biên dịch rộng" như câu trả lời này nói.

1
Rõ ràng, chính trình biên dịch xác định các macro này chứ không phải Visual Studio (IDE). Cảm ơn rất nhiều cho câu trả lời này!
Niklas R

NDEBUG không được xác định khi sử dụng các mẫu ứng dụng từ Windows Driver Kit 8.1. Trong trường hợp này, bạn có thể cần phải dựa vào _DEBUG.
navossoc

53

Là tiêu chuẩn NDEBUG?

Vâng, đó là một macro tiêu chuẩn với ngữ nghĩa "Không gỡ lỗi" cho các tiêu chuẩn C89, C99, C ++ 98, C ++ 2003, C ++ 2011, C ++ 2014. Không có_DEBUG macro trong các tiêu chuẩn.

Tiêu chuẩn C ++ 2003 gửi người đọc tại "trang 326" tại "17.4.2.1 Tiêu đề" tới tiêu chuẩn C.

Đó là NDEBUG tương tự như Điều này giống như thư viện C chuẩn.

Trong C89 (lập trình viên C gọi tiêu chuẩn này là tiêu chuẩn C) trong phần "4.2 CHẨN ĐOÁN", người ta đã nói

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

Nếu NDEBUG được định nghĩa là tên macro tại điểm trong tệp nguồn được bao gồm, macro xác nhận được định nghĩa đơn giản là

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

Nếu nhìn vào ý nghĩa của các _DEBUGmacro trong Visual Studio https://msdn.microsoft.com/en-us/l Library / b0084kay.aspx thì sẽ thấy rằng macro này được tự động xác định bởi phiên bản thư viện thời gian chạy ngôn ngữ của bạn.


50

Tôi dựa vào NDEBUG, bởi vì đó là người duy nhất có hành vi được chuẩn hóa trên các trình biên dịch và triển khai (xem tài liệu về macro xác nhận tiêu chuẩn). Logic tiêu cực là một tốc độ dễ đọc nhỏ, nhưng đó là một thành ngữ phổ biến mà bạn có thể nhanh chóng thích nghi.

Dựa vào một cái gì đó giống như _DEBUGsẽ dựa vào một chi tiết triển khai của một trình biên dịch và triển khai thư viện cụ thể. Trình biên dịch khác có thể hoặc không thể chọn cùng một quy ước.

Tùy chọn thứ ba là xác định macro của riêng bạn cho dự án của bạn, điều này khá hợp lý. Có macro của riêng bạn cung cấp cho bạn tính di động trong các triển khai và nó cho phép bạn bật hoặc tắt mã gỡ lỗi của mình một cách độc lập với các xác nhận. Mặc dù, nói chung, tôi khuyên bạn không nên có các loại thông tin gỡ lỗi khác nhau được bật tại thời điểm biên dịch, vì nó gây ra sự gia tăng số lượng cấu hình bạn phải xây dựng (và kiểm tra) vì lợi ích nhỏ có thể tranh cãi.

Với bất kỳ tùy chọn nào trong số các tùy chọn này, nếu bạn sử dụng mã của bên thứ ba như một phần của dự án của mình, bạn sẽ phải biết về quy ước mà nó sử dụng.


1
#if !defined(NDEBUG)<- @hostileFork không phải là ý bạn sao? #ifkhông #ifdef?
Bob Stein

1
Nhận xét ban đầu được sửa chữa thông qua @BobStein: "Điều gì đó tôi đã làm để (giảm nhẹ) khả năng đọc" speedbump "là khi nói về việc sử dụng điều kiện không gỡ lỗi #ifdef NDEBUG... nhưng sau đó đặc biệt chú ý đến logic tiêu cực #if !defined(NDEBUG). Nếu không thì hơi khó để bắt được n #ifndef NDEBUG"
HostileFork nói không tin tưởng vào

17

Các macro NDEBUGkiểm soát xem các assert()câu lệnh có hoạt động hay không.

Theo quan điểm của tôi, nó tách biệt với mọi gỡ lỗi khác - vì vậy tôi sử dụng một cái gì đó ngoài NDEBUGviệc kiểm soát thông tin gỡ lỗi trong chương trình. Những gì tôi sử dụng khác nhau, tùy thuộc vào khung tôi đang làm việc; các hệ thống khác nhau có các macro cho phép khác nhau và tôi sử dụng bất cứ thứ gì phù hợp.

Nếu không có khung, tôi sẽ sử dụng tên mà không có dấu gạch dưới hàng đầu; những điều này có xu hướng được dành riêng cho 'việc thực hiện' và tôi cố gắng tránh các vấn đề với xung đột tên - gấp đôi khi tên đó là một macro.


Bạn có thể giải thích lý do tại sao bạn xem xét các khẳng định khác biệt với các loại gỡ lỗi khác không? Trong kịch bản nào bạn muốn cái này chứ không phải cái kia?
Adrian McCarthy

4
Tôi tiếp tục khẳng định hoạt động ngay cả khi tôi không biên dịch các phương tiện gỡ lỗi hoặc theo dõi khác vào mã. Khẳng định xác định các tình huống không thể. Truy tìm và gỡ lỗi chung là IMO hoàn toàn tách biệt với điều đó.
Jonathan Leffler

2
@AdrianMcCarthy: nếu bạn bật TẤT CẢ gỡ lỗi, điều đó có thể khiến các chương trình chạy chậm TUYỆT VỜI. Vì vậy, thông thường để phân loại các loại gỡ lỗi và cho phép mọi người bật / tắt chúng một cách riêng biệt. MSVC có hai hoặc ba cái họ sử dụng để bật / tắt các gỡ lỗi khác nhau cho thư viện chuẩn, như std :: vector.
Vịt Mooing

@MooingDuck: Đồng ý, nhưng phân biệt giữa 'gỡ lỗi có sẵn và được bật' và 'gỡ lỗi có sẵn nhưng bị vô hiệu hóa' và 'gỡ lỗi không khả dụng'. Quyết định có sẵn / không khả dụng là vấn đề thời gian biên dịch (trong mã C hoặc C ++) và sau đó bật / tắt là quyết định thời gian chạy khi gỡ lỗi có sẵn. Chỉ các hệ thống gỡ lỗi thô sơ nhất mới hoạt động với chế độ 'khả dụng có nghĩa là được bật'. (Điều đó nói rằng, dầu thô có thể có hiệu quả, và có rất nhiều dầu thô - nhưng đủ hiệu quả - hệ thống gỡ lỗi ngoài tự nhiên!)
Jonathan Leffler

2
@MooingDuck: Có, một số mã gỡ lỗi có thể thay đổi chậm. Trong trường hợp đó, bạn có thể muốn một cách để kiểm soát xem mã chậm có chạy độc lập với các kiểm tra tầm thường hay không. Nhưng điều đó không giống như đặt các xác nhận vào một danh mục và #ifmã được kiểm soát trong một danh mục khác. assert(huge_object.IsValid());có thể chậm trong khi assert(ptr != nullptr);có lẽ không. Tôi đồng ý với Jonathan rằng việc ghi nhật kýtheo dõi có lẽ phải khác biệt với các xác nhận, ít nhất là trong các dự án lớn hơn, nhưng tôi không nghĩ đến việc ghi nhật ký hoặc theo dõi là mã gỡ lỗi, đó là lý do tại sao tôi yêu cầu làm rõ.
Adrian McCarthy

6

Hãy nhất quán và nó không quan trọng cái nào. Ngoài ra, nếu vì lý do nào đó, bạn phải can thiệp với một chương trình hoặc công cụ khác bằng cách sử dụng một mã định danh DEBUG nhất định, thật dễ dàng để làm

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

4

Thật không may DEBUGlà quá tải nặng. Chẳng hạn, nên luôn luôn tạo và lưu tệp pdb cho các bản dựng ĐÁNG TIN CẬY. Có nghĩa là một trong những -Zxcờ và -DEBUGtùy chọn liên kết. Trong khi _DEBUGliên quan đến các phiên bản gỡ lỗi đặc biệt của thư viện thời gian chạy như các cuộc gọi đến mallocfree. Sau đó NDEBUGsẽ vô hiệu hóa các xác nhận.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.