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

时间:2013-11-20 01:24:55

标签: c c-preprocessor preprocessor-directive

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

#if VERSION > 100
/* Compiling here */
#endif

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

#define VERSION "101"

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

#if STRING_TO_NUMBER(VERSION) > 100
/* Compiling here */
#endif

请问有可能吗?

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

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

棘手的部分是,VERSION被定义为一个字符串,带来了这个问题。

2 个答案:

答案 0 :(得分:3)

如果您需要与预处理器进行交互,以设置其他#defines或有条件#include个不同的标头。直到你可以将VERSION“固定”为整数......

我能想到的唯一一件事就是创建一个定义PROPER_VERSION的小头文件,并通过将每个文件命名为版本号来包含它。所以你在这里创建:

100:
#define PROPER_VERSION 100

101:
#define PROPER_VERSION 101

102:
#define PROPER_VERSION 102

然后你需要添加以下内容:

#include VERSION

然后根据需要使用PROPER_VERSION

#if PROPER_VERSION > 100
...

它不优雅,但我看不到你能做的任何其他事情。您可以自动生成VERSION文件。

答案 1 :(得分: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
}

通过在未使用的分支中插入对未定义函数的调用,可以很容易地证明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;
}

(见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) ... 。结合一些可能称为滥用模板的内容,允许条件声明:

{{1}}

http://ideone.com/H1sdNg处的愚蠢例子)