Czy używanie makr C / C ++ jako skrótu do kompilacji warunkowej jest dobrą praktyką?

13

Powiedzmy, że chcę mieć w kodzie kilka typów komunikatów wyjściowych. Jednym z nich jest DEBUG, który jest drukowany tylko wtedy, gdy kod jest kompilowany w trybie debugowania.

Zwykle musiałbym napisać coś takiego

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

co jest dość kłopotliwe i denerwujące w użyciu w wielu miejscach.

Czy dobrą praktyką jest definiowanie makra dla fragmentu kodu, abyś mógł z niego korzystać w ten sposób?

MSG_DEBUG("Debug message")

A może istnieje inny, bardziej elegancki sposób radzenia sobie z tym bez makr? Interesują mnie możliwe rozwiązania zarówno w C, jak i C ++, ponieważ używam obu języków w różnych projektach.

Eenoku
źródło
Pytanie, dlaczego po prostu nie umieściłbyś kodu warunkowego w funkcji i nie wywołało tego, nie jest jasne. Czy jest jakieś inne ograniczenie, które by temu zapobiec?
Alex
@gnat Wspomniane przez ciebie pytanie jest tak szerokie, że większość ludzi nie połączy go z tym tematem, zwłaszcza gdy będą szukać tego konkretnego pytania w Internecie.
Eenoku,
3
Twoje pytanie jest oznaczone zarówno c, jak i c ++ , jednak są to całkiem różne języki. Czy możesz wyjaśnić, o którym mówisz? Twój przykład byłby w porządku w C, ale może być lepiej zaimplementowany constexpr ifna przykład w C ++.
Jörg W Mittag,
1
Nawiasem mówiąc, diagnostyka powinna przejść do STDERR. Ponadto, dlaczego nie zrobić to zależy NDEBUGjak assert()robi zamiast? Następnie możesz zdefiniować go tak #define DEBUG_MSG(MSG) assert(std::cerr << MSG), który testuje również stan strumienia.
Deduplicator,

Odpowiedzi:

19

Jasne, jeśli nie masz nic przeciwko używaniu makr, to zdefiniowanie sparametryzowanego zamiast powtarzania tego samego kodu warunkowego jest z pewnością bardziej pożądane pod każdym względem dobrego kodowania.

Czy w ogóle powinieneś używać makr? Moim zdaniem należy, ponieważ jest akceptowaną praktyką w C, a wszelkie makro mniej rozwiązanie wymaga co najmniej coś wykonywane nawet poza trybem debugowania. Typowy programista C wybierze nieco brzydkie makro w stosunku do niepotrzebnego wysiłku w czasie wykonywania.

Kilian Foth
źródło
13

Jest tu element osobistych preferencji, ale w C ++ wolę to zrobić w pliku nagłówkowym:

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

Tak, że funkcja jest wbudowana w kompilacje wersji, ale jest właściwą funkcją w kompilacji debugowania, dzięki czemu można mieć właściwe sprawdzanie typu, rozsądne komunikaty o błędach itp., A także możliwość dodania dalszej funkcjonalności (może rejestrowania?) Później.

Oczywiście musisz również zawrzeć odpowiednią definicję funkcji w .cpppliku w #ifdef _DEBUGbloku.

Jack Aidley
źródło
Ale narzut jest nadal obecny, prawda?
Eenoku,
7
Jeśli Twój kompilator wygeneruje kod do wywołania znanej pustej funkcji w kompilacji wydania, pierwszą i największą rzeczą, którą musisz zrobić, aby poprawić wydajność, jest uzyskanie znacznie lepszego kompilatora. To naprawdę trywialna optymalizacja.
David Thornley,
@Eenoku Nie, jak mówi David, zostanie on usunięty przez dowolny kompilator, którego należy użyć.
Jack Aidley,
3
Jest tu zasadnicza różnica: makro (w zależności od tego, jak jest napisane) nie oceniałoby wyrażeń argumentu, podczas gdy funkcja zawsze. Ponadto, niezdefiniowanym zachowaniem jest przekazywanie nietrywialnych argumentów do funkcji varargs (i zwykle wyzwala ostrzeżenia kompilatora).
Sebastian Redl,
2

Zdecydowanie upewnij się, że nie postępujesz zgodnie ze wskazówkami kodu podanymi przez Twój zespół. Upewnij się, że żaden inny kod w systemie nie próbuje osiągnąć tej samej funkcjonalności poprzez ogólny warunek if.

James O
źródło