C/C++预处理器中是否有指令将字符串转换为数字?

use*_*470 8 c c-preprocessor preprocessor-directive

我希望在我的代码中添加一些条件指令来控制不同的构建,例如:

#if VERSION > 100
/* Compiling here */
#endif
Run Code Online (Sandbox Code Playgroud)

问题是"VERSION"在其他代码中我无法改变.它被定义为一个字符串:

#define VERSION "101"
Run Code Online (Sandbox Code Playgroud)

我想知道是否有某种宏或指令将字符串转换为数字,所以我可以简单地做

#if STRING_TO_NUMBER(VERSION) > 100
/* Compiling here */
#endif
Run Code Online (Sandbox Code Playgroud)

这可能吗?

PS.看来我的描述不太清楚.此要求的主要目的是控制版本分支.例如,在旧版本的100版之前,此程序需要old_function().在此版本之后,所有功能都已迁移到new_function.所以我需要编写这样的代码:

#if VERSION >= 100
    old_function();
#else
    new_function();
#endif
#if VERSION >= 100
int old_function()
{
    ...
}
#else
int new_function()
{
    ...
}
#endif
Run Code Online (Sandbox Code Playgroud)

您可以看到只编译了一个函数.因此,必须在预处理阶段决定条件,而不是在运行时.

棘手的部分是,VERSION被定义为一个字符串,它提出了这个问题.

ric*_*ici 2

只要您不需要在 上进行声明或预处理器定义条件VERSION,并且只要您确信该VERSION字符串将只是一个没有前导零的整数(这两者都可能要求过高),如果您的编译器有一个相当有效的常量表达式计算器,您也许可以在编译时执行此操作。

例如,gcc 4.8 将优化掉以下if测试,只留下适当的手臂:

if (strlen(VERSION) > 3 || (strlen(VERSION) == 3 && strcmp(VERSION, "100") > 0)) {
  // code if VERSION is at least "101"
} else {
  // code if VERSION is "100" or less
}
Run Code Online (Sandbox Code Playgroud)

if通过在未使用的分支中插入对未定义函数的调用,可以轻松证明该语句只有一个分支在编译后幸存下来。使用 gcc(和 clang),并启用优化,不会产生链接器错误:

#include <stdio.h>
#include <string.h>
#define VERSION "101"
// This function is not available for linking
int unknown_function();
// This one is in standard library
int rand();
int main(void) {
    int x;
    if (strlen(VERSION) > 3 || (strlen(VERSION) == 3 && strcmp(VERSION, "100") > 0)) {
      // code if VERSION is at least "101"
      x = rand();
    } else {
      // code if VERSION is "100" or less
      x = unknown_function();
    }
    printf("%d\n", x);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

(参见http://ideone.com/nGLGTH


在C++11中,有一个更清晰的编译时版本。您可以创建constexpr一个atoi. 结合一些人可能称之为模板的滥用,允许条件声明:

constexpr int const_atoi(const char* num, int accum=0) {
  return *num ? const_atoi(num+1, accum*10 + (*num - '0')) : accum;
}

template<bool V_GT_100> struct MoreOrLess_Impl;
template<> struct MoreOrLess_Impl<false> {
  // Old prototype
  void doit(double x) {...}
};
template<> struct MoreOrLess_Impl<true> {
  // New prototype
  void doit(long double x) {...}
};
using MoreOrLess = MoreOrLess_Impl<(const_atoi(VERSION) > 100)>;

// ...
// ... MoreOrLess::doit(x) ...
Run Code Online (Sandbox Code Playgroud)

(愚蠢的例子位于http://ideone.com/H1sdNg