条件逻辑和跨平台处理

简而言之,条件预处理逻辑是关于使用宏定义使代码逻辑可用或不可用于编译。

三个突出的用例是:

  • 不同的应用程序配置文件 (例如调试,发布,测试,优化)可以是同一个应用程序的候选者(例如,使用额外的日志记录)。
  • 跨平台编译 - 单个代码库,多个编译平台。
  • 利用通用代码库来实现多个应用程序版本 (例如软件的 Basic,Premium 和 Pro 版本) - 功能略有不同。

示例 a: 用于删除文件的跨平台方法(说明性):

#ifdef _WIN32
#include <windows.h> // and other windows system files
#endif
#include <cstdio>

bool remove_file(const std::string &path) 
{
#ifdef _WIN32
  return DeleteFile(path.c_str());
#elif defined(_POSIX_VERSION) || defined(__unix__)
  return (0 == remove(path.c_str()));
#elif defined(__APPLE__)
  //TODO: check if NSAPI has a more specific function with permission dialog
  return (0 == remove(path.c_str()));
#else 
#error "This platform is not supported"
#endif
}

_WIN32__APPLE____unix__ 这样的宏通常由相应的实现预定义。

示例 b: 为调试版本启用其他日志记录:

void s_PrintAppStateOnUserPrompt()
{
    std::cout << "--------BEGIN-DUMP---------------\n"
              << AppState::Instance()->Settings().ToString() << "\n"
#if ( 1 == TESTING_MODE ) //privacy: we want user details only when testing
              << ListToString(AppState::UndoStack()->GetActionNames())
              << AppState::Instance()->CrntDocument().Name() 
              << AppState::Instance()->CrntDocument().SignatureSHA() << "\n"
#endif
              << "--------END-DUMP---------------\n"
}

示例 c: 在单独的产品构建中启用高级功能(注意:这是说明性的。通常更好的做法是在不需要重新安装应用程序的情况下解锁功能)

void MainWindow::OnProcessButtonClick()
{
#ifndef _PREMIUM
    CreatePurchaseDialog("Buy App Premium", "This feature is available for our App Premium users. Click the Buy button to purchase the Premium version at our website");
    return;
#endif
    //...actual feature logic here
}

一些常见的技巧:

在调用时定义符号:

可以使用预定义符号调用预处理器(可选的初始化)。例如,此命令(gcc -E 仅运行预处理器)

gcc -E -DOPTIMISE_FOR_OS_X -DTESTING_MODE=1 Sample.cpp

以与将 #define OPTIMISE_FOR_OS_X#define TESTING_MODE 1 添加到 Sample.cpp 顶部时相同的方式处理 Sample.cpp。

确保定义宏:

如果未定义宏并且比较或检查其值,则预处理器几乎总是默默地假定值为 0。有几种方法可以解决这个问题。一种方法是假设默认设置表示为 0,并且需要明确地完成任何更改(例如,应用程序构建配置文件)(例如,默认情况下为 ENABLE_EXTRA_DEBUGGING = 0,设置 -DENABLE_EXTRA_DEBUGGING = 1 以进行覆盖)。另一种方法是使所有定义和默认值都明确。这可以通过 #ifndef#error 指令的组合来实现:

#ifndef (ENABLE_EXTRA_DEBUGGING)
// please include DefaultDefines.h if not already included.
#    error "ENABLE_EXTRA_DEBUGGING is not defined"
#else
#    if ( 1 == ENABLE_EXTRA_DEBUGGING )
  //code
#    endif
#endif