Việc sử dụng các macro C / C ++ như một lối tắt để biên dịch có điều kiện có phải là một cách thực hành tốt không?


13

Giả sử tôi muốn có một số loại thông báo đầu ra trong mã của mình. Một trong số đó là DEBUG, chỉ được in khi mã được biên dịch ở chế độ Gỡ lỗi.

Thông thường tôi phải viết một cái gì đó như

#ifdef DEBUG
    std::cout << "Debug message" << std::endl;
#endif

đó là khá cồng kềnh và khó chịu để sử dụng ở nhiều nơi.

Có phải là một cách thực hành tốt để xác định một macro cho đoạn mã, vì vậy bạn sẽ sử dụng nó theo cách này?

MSG_DEBUG("Debug message")

Hoặc có cách nào khác, thanh lịch hơn để đối phó với nó mà không cần macro? Tôi quan tâm đến các giải pháp khả thi cả trong C và C ++, vì tôi đang sử dụng cả hai ngôn ngữ trong các dự án khác nhau.



Không rõ ràng từ câu hỏi tại sao bạn sẽ không đặt mã điều kiện vào một hàm và gọi nó. Có một số ràng buộc khác sẽ ngăn chặn điều đó?
Alex

@gnat Câu hỏi bạn đã đề cập rất rộng, hầu hết mọi người sẽ không kết nối nó với chủ đề này, đặc biệt là khi họ đang tìm kiếm câu hỏi cụ thể này trên Internet.
Eenoku

3
Câu hỏi của bạn được gắn thẻ bằng cả cc ++ , tuy nhiên, đó là những ngôn ngữ khá khác nhau. Bạn có thể làm rõ cái nào bạn đang nói về? Ví dụ của bạn sẽ hoàn toàn tốt trong C, nhưng có thể được triển khai tốt hơn với constexpr ifC ++.
Jörg W Mittag

1
Như một bên, chẩn đoán nên đi đến STDERR. Ngoài ra, tại sao không làm cho nó phụ thuộc vào NDEBUGnhư assert()thay vào đó? Sau đó, bạn có thể định nghĩa nó như thế nào #define DEBUG_MSG(MSG) assert(std::cerr << MSG), cũng kiểm tra trạng thái luồng.
Ded repeatator

Câu trả lời:


19

Chắc chắn, nếu bạn ổn với việc sử dụng macro ở vị trí đầu tiên, thì việc xác định một tham số được tham số hóa thay vì tiếp tục lặp lại cùng một mã điều kiện chắc chắn là tốt hơn bởi bất kỳ biện pháp mã hóa tốt nào.

Bạn có nên sử dụng macro không? Theo quan điểm của tôi, bạn nên, vì nó được chấp nhận thực hành trong C và bất kỳ giải pháp không có macro nào cũng sẽ yêu cầu ít nhất một cái gì đó được thực thi ngay cả ngoài chế độ gỡ lỗi. Lập trình viên C điển hình sẽ chọn một macro hơi xấu xí so với nỗ lực thời gian không cần thiết bất cứ lúc nào.


13

Có một yếu tố sở thích cá nhân ở đây, nhưng trong C ++, tôi thích làm điều này trong tệp tiêu đề:

#ifdef _DEBUG
    void DebugMessage(...);
#else
    inline void DebugMessage(...) {}
#endif

Vì vậy, chức năng được nội tuyến trong các bản dựng phát hành, nhưng là một chức năng phù hợp trong bản dựng gỡ lỗi để bạn có thể kiểm tra loại thích hợp, thông báo lỗi hợp lý, v.v. và khả năng thêm chức năng (có thể đăng nhập?) Sau này.

Rõ ràng, bạn cũng cần bao hàm định nghĩa tương ứng của hàm trong .cpptệp trong một #ifdef _DEBUGkhối.


Nhưng chi phí cuộc gọi vẫn còn hiện diện ở đây, phải không?
Eenoku

7
Nếu trình biên dịch của bạn sẽ tạo mã để gọi một hàm trống đã biết trong bản dựng phát hành, điều đầu tiên và lớn nhất bạn cần làm để cải thiện hiệu quả là có được trình biên dịch tốt hơn nhiều. Đây thực sự là tối ưu hóa tầm thường.
David Thornley

@Eenoku Không, như David nói, nó sẽ bị xóa bởi bất kỳ trình biên dịch nào bạn nên sử dụng.
Jack Aidley

3
Có một sự khác biệt chính ở đây: macro (tùy thuộc vào cách viết) sẽ không đánh giá các biểu thức đối số của nó, trong khi hàm luôn luôn như vậy. Ngoài ra, đó là hành vi không xác định để chuyển các đối số không tầm thường sang các hàm varargs (và thường kích hoạt các cảnh báo của trình biên dịch).
Sebastian Redl


2

Chắc chắn, chỉ cần đảm bảo rằng bạn không bước vào các nguyên tắc mã do nhóm của bạn đưa ra. Đảm bảo không có mã nào khác trong hệ thống cố gắng đạt được chức năng tương tự thông qua một điều kiện chung.

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.