[embedded c]debug prints netter in een functie of macro mogelijk?

Stijnos

Golden Member

Even een puur software vraagje, maar gezien hier toch de nodige embedded specialisten zitten vind ik hem hier wel passen.

Ik was even benieuwd of iemand misschien een oplossing weet.

Ik heb in mijn code de nodige debug prints over een uart, die zijn voor tracing cruciaal en erg handig. In de uiteindelijke release wil ik geen onzin voor een eind gebruiker geprint hebben.
Dat zit nu ongeveer zo in elkaar:


#ifdef ENABLE_DEBUG_PRINTS
    printf("This string should only be printed if debug prints are enabled and with avriable arguments like %d and %08x",
    counter, hexAddress);
#endif

Echter nu stata mijn code vol met dit soort regels en met name die #ifdefs maken de code lelijk en slechter leesbaar.

Het zou layout technisch veel mooier zijn als het gewoon een oneliner kan zijn.
Ik heb al een functie gemaakt waar de #ifdef in die functie zit. Zoals dit:


static void DebugPrint(const char* pStringFormat, ...) {
#ifdef ENABLE_DEBUG_PRINTS
    va_list args;
    va_start(args, pStringFormat);
    printf(pStringFormat, args);
    va_end(args);
#else
    // Do nothing if ENABLE_DEBUG_PRINTS is not defined
    (void)pStringFormat;
#endif

Dit werkt en houd de code een stuk overzichtelijker, echt het grootste nadeel hiervan is dat nu alle string literals toch altijd mee gecompileerd worden, ook al worden ze in de functie niet gebruikt.
Ik doe de (void)pStringFormat om een warning over een unused argument te suppressen, gezien ik daar geen suppress in de keil compiler voor kan vinden.
Ik wil al deze strings überhaubt niet meegecompileerd hebben indien de debug prints niet enabled zijn.
Iemand tips? Is het een kwestie van compiler configuratie of is het inherent aan deze oplossing.
Ik zat te denken om het met een macro op te lossen ipv met een functie, maar dan weet ik niet hoe dat te doen, gezien je bij een printf een variabele argument list hebt.
zou een inline functie hier nog iets aan bijdragen?

Meeste compilers ondersteunen wel varaidic macros. Verschilt echter per compiler hoe het precies moet.

Dus als je bereid bent je code (deels) compiler-specifiek te maken, google "Keil variadic macros"

Voor GCC kun je ##_VA_ARGS gebruiken:


#define DEBUG_PRINTF(format, ...) do { \
#ifdef DEBUGGING \
    printf(format, ##_VA_ARGS); \
#endif \
}while(0)

// usage:
DEBUG_PRINTF("The answer id %i\n", 42);

Voor C++ 20 is bij mijn weten __VA_ARGS__ voor hetzelfde doel gedefinieerd.

#ifdef DEBUGGING
#define DEBUG_PRINTF printf
#else
#define DEBUG_PRINTF (void)//
#endif

O-)

Meep! Meep!

Gewoon

#ifdef ENABLE_DEBUG_PRINTS
...
#endif

blijven gebruiken dan compileerd er niets mee en kost het geen extra resources.

Ik zou kiezen voor roadrunner zijn oplossing. Of inline functies gebruiken.

PE2BAS

De oplossing van roadrunner werkt niet tgv de variabele lijst argumenten. Daarvoor moet je naar de oplossing van blurp.

En inderdaad, die resulteert ook in geen code zodra je de macro uitschakelt.

Een variant hierop gaat zo:


#define ENABLE_DEBUG 0

#if ENABLE_DEBUG
  #define DEBUG_PRINT(...) SerialPort.printf(__VA_ARGS__)
#else
  #define DEBUG_PRINT(...)
#endif

En die kun je dan zo gebruiken:

   DEBUG_PRINT(PSTR("- EndFillByte : 0x%02X\n"), c);

Correctie.

De methode van roadrunner84 blijkt toch ook te werken. Dat had ik niet gedacht.


#define ENABLE_DEBUG 0

#if ENABLE_DEBUG
   #define DEBUG_PRINT printf
#else
   #define DEBUG_PRINT (void)
#endif

Via die macro wordt de volgende code:

   DEBUG_PRINT(PSTR("- EndFillByte : 0x%02X\n"), c);

Omgezet naar (Debug aan)

   printf(PSTR("- EndFillByte : 0x%02X\n"), c);

Ofwel naar (Debug uit)

   (void)(PSTR("- EndFillByte : 0x%02X\n"), c);

In dat laatste geval blijft er uiteindelijk toch weinig van over, precies wat je wilt.

* Getest met AvrGcc.

Het werkt, maar ik vind dit wel duidelijker


#define ENABLE_DEBUG 0

#if ENABLE_DEBUG
  #define DEBUG_PRINT(...) SerialPort.printf(__VA_ARGS__)
#else
  #define DEBUG_PRINT(...)
#endif

Mijn suggestie van de inline, ik verwacht dat het resultaat hetzelfde is. Aangezien bij een ifndef de boel leeg blijft.

PE2BAS

Ik gebruik wel eens een


int debug = 0;

en dan een define die test of een bepaald bitje in debug aanstaat. Kan je dynamisch kiezen wat je voor debug wilt zien, tot 32 klassen....

Je krijgt dan iets als

DPRINTF (D_TXRX, "transmitting %d bytes", ntx);

Dat kan naar "niets" compileren met debug uit en controleert de globale debug variabele of het D_TXRX vlaggetje aanstaat als het wel compiletime enabled is.

Dit soort debugging maak ik altijd een keer als ik een lastig debug probleem heb, zet het dan 2 of 3 x aan en uit totdat ik de debugging maar gewoon runtime uit zet.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Stijnos

Golden Member

thanks voor de tips blurp en roadrunner, ik ga ze beide eens proberen.

Op maandag 11 november 2024 22:47:35 schreef rew:
Ik gebruik wel eens een


int debug = 0;

en dan een define die test of een bepaald bitje in debug aanstaat. Kan je dynamisch kiezen wat je voor debug wilt zien, tot 32 klassen....

Je krijgt dan iets als

DPRINTF (D_TXRX, "transmitting %d bytes", ntx);

Dat kan naar "niets" compileren met debug uit en controleert de globale debug variabele of het D_TXRX vlaggetje aanstaat als het wel compiletime enabled is.

Dit soort debugging maak ik altijd een keer als ik een lastig debug probleem heb, zet het dan 2 of 3 x aan en uit totdat ik de debugging maar gewoon runtime uit zet.

Leuke methode, dat kan je dan ook wat cleaner/gebruksvriendelijker maken met extra defines


#define D_EN_TXRX (1 << 5) // in dit voorbeeld dus bit 5

#define DEBUG (D_EN_TXRX | D_EN_TIMER | D_EN_LOGGING)

#if DEBUG & D_EN_TXRX
#define D_TXRX
#endif

Waarbij je zelfs een groot deel in een losse header kan zetten:


#ifndef DEBUG
  #ifndef DEBUG_PRE_SET
    #define DEBUG_PRE_SET

    #define D_EN_TXRX (1 << 5)

  #endif
#else
  #ifndef DEBUG_POST_SET
    #define DEBUG_POST_SET

    #if DEBUG & D_EN_TXRX
      #define D_TXRX
    #endif

    #ifdef DEBUG
      #define DPRINTF(verbosity, ...) debug_printf(verbosity, __VA_ARGS__)
    #else
      #define DPRINTF(...) (void)
    #endif
  #endif
#endif

En dan in je C file:

#include "debug.h"
#define DEBUG (D_EN_TXRX | D_EN_TIMER | D_EN_LOGGING)
#include "debug.h"
Meep! Meep!