条件包含和条件函数签名修改

为了有条件地包含一个代码块,预处理器有几个指令(例如 #if#ifdef#else#endif 等)。

/* 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

普通 C 关系运算符可用于 #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

#if 指令的行为类似于 C if 语句,它只包含整数常量表达式,并且不包含强制转换。它支持一个额外的一元运算符 defined( identifier ),如果定义了标识符则返回 1,否则返回 0

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

条件函数签名修改

在大多数情况下,应用程序的发布版本应该具有尽可能少的开销。但是,在测试临时构建期间,其他日志和有关问题的信息可能会有所帮助。

例如,假设有一些函数 SHORT SerOpPluAllRead(PLUIF *pPif, USHORT usLockHnd),在进行测试构建时,需要生成关于其使用的日志。但是,此功能在多个地方使用,并且希望在生成日志时,部分信息是知道调用函数的位置。

因此,使用条件编译,你可以在包含文件声明函数中使用以下内容。这将使用函数的调试版本替换函数的标准版本。预处理器用于替换函数 SerOpPluAllRead() 的调用,调用函数 SerOpPluAllRead_Debug(),带有两个附加参数,文件名和函数使用位置的行号。

条件编译用于选择是否使用调试版本覆盖标准函数。

#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

这允许你使用一个版本覆盖函数 SerOpPluAllRead() 的标准版本,该版本将在调用函数的文件中提供文件名和行号。

有一个重要的考虑因素: 使用此函数的任何文件都必须包含使用此方法的头文件,以便预处理器修改函数。否则,你将看到链接器错误。

函数的定义如下所示。此源的作用是请求预处理器将函数 SerOpPluAllRead() 重命名为 SerOpPluAllRead_Debug() 并修改参数列表以包含两个附加参数,指向调用函数的文件名称的指针以及文件中的行号使用该功能。

#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;
}