C Language Inclusione condizionale e modifica della firma della funzione condizionale


Esempio

Per includere condizionalmente un blocco di codice, il preprocessore ha diverse direttive (ad esempio #if , #ifdef , #else , #endif , ecc.).

/* Defines a conditional `printf` macro, which only prints if `DEBUG`
 * has been defined
 */
#ifdef DEBUG
#define DLOG(x) (printf(x))
#else
#define DLOG(x)
#endif

Gli operatori relazionali C normali possono essere utilizzati per la condizione #if

#if __STDC_VERSION__ >= 201112L
/* Do stuff for C11 or higher */
#elif __STDC_VERSION__ >= 199901L
/* Do stuff for C99 */
#else
/* Do stuff for pre C99 */
#endif

Le direttive #if si comportano in modo analogo all'istruzione C if , devono contenere solo espressioni costanti integrali e nessun cast. Supporta un operatore unario aggiuntivo, defined( identifier ) , che restituisce 1 se l'identificatore è definito e 0 altrimenti.

#if defined(DEBUG) && !defined(QUIET)
#define DLOG(x) (printf(x))
#else
#define DLOG(x)
#endif

Modifica firma funzione condizionale

Nella maggior parte dei casi, si prevede che il rilascio di build di un'applicazione abbia il minor overhead possibile. Tuttavia, durante il test di una build provvisoria, possono essere utili log aggiuntivi e informazioni sui problemi rilevati.

Ad esempio, supponiamo che ci sia una qualche funzione SHORT SerOpPluAllRead(PLUIF *pPif, USHORT usLockHnd) che quando si esegue una build di test è necessario generare un log relativo al suo utilizzo. Tuttavia questa funzione viene utilizzata in più punti e si desidera che quando si genera il registro, parte delle informazioni sia sapere da dove viene chiamata la funzione.

Pertanto, utilizzando la compilazione condizionale è possibile avere qualcosa di simile al seguente nel file di inclusione che dichiara la funzione. Sostituisce la versione standard della funzione con una versione di debug della funzione. Il preprocessore viene utilizzato per sostituire le chiamate alla funzione SerOpPluAllRead() con le chiamate alla funzione SerOpPluAllRead_Debug() con due argomenti aggiuntivi, il nome del file e il numero di riga di dove viene utilizzata la funzione.

La compilazione condizionale viene utilizzata per scegliere se sovrascrivere la funzione standard con una versione di debug o meno.

#if 0
// function declaration and prototype for our debug version of the function.
SHORT   SerOpPluAllRead_Debug(PLUIF *pPif, USHORT usLockHnd, char *aszFilePath, int nLineNo);

// macro definition to replace function call using old name with debug function with additional arguments.
#define SerOpPluAllRead(pPif,usLock) SerOpPluAllRead_Debug(pPif,usLock,__FILE__,__LINE__)
#else
// standard function declaration that is normally used with builds.
SHORT   SerOpPluAllRead(PLUIF *pPif, USHORT usLockHnd);
#endif

Ciò consente di sostituire la versione standard della funzione SerOpPluAllRead() con una versione che fornirà il nome del file e il numero di riga nel file in cui viene chiamata la funzione.

C'è una considerazione importante: qualsiasi file che utilizza questa funzione deve includere il file di intestazione in cui viene utilizzato questo approccio in modo che il preprocessore possa modificare la funzione. Altrimenti vedrai un errore del linker.

La definizione della funzione sarebbe simile alla seguente. Ciò che fa questa fonte è richiedere che il preprocessore rinomina la funzione SerOpPluAllRead() in SerOpPluAllRead_Debug() e che modifichi l'elenco degli argomenti per includere due argomenti aggiuntivi, un puntatore al nome del file in cui è stata chiamata la funzione e il numero di riga nel file in cui viene utilizzata la funzione.

#if defined(SerOpPluAllRead)
// forward declare the replacement function which we will call once we create our log.
SHORT    SerOpPluAllRead_Special(PLUIF *pPif, USHORT usLockHnd);

SHORT    SerOpPluAllRead_Debug(PLUIF *pPif, USHORT usLockHnd, char *aszFilePath, int nLineNo)
{
    int iLen = 0;
    char  xBuffer[256];

    // only print the last 30 characters of the file name to shorten the logs.
    iLen = strlen (aszFilePath);
    if (iLen > 30) {
        iLen = iLen - 30;
    }
    else {
        iLen = 0;
    }

    sprintf (xBuffer, "SerOpPluAllRead_Debug(): husHandle = %d, File %s, lineno = %d", pPif->husHandle, aszFilePath + iLen, nLineNo);
    IssueDebugLog(xBuffer);

    // now that we have issued the log, continue with standard processing.
    return SerOpPluAllRead_Special(pPif, usLockHnd);
}

// our special replacement function name for when we are generating logs.
SHORT    SerOpPluAllRead_Special(PLUIF *pPif, USHORT usLockHnd)
#else
// standard, normal function name (signature) that is replaced with our debug version.
SHORT   SerOpPluAllRead(PLUIF *pPif, USHORT usLockHnd)
#endif
{
    if (STUB_SELF == SstReadAsMaster()) {
        return OpPluAllRead(pPif, usLockHnd);
    } 
    return OP_NOT_MASTER;
}