【问题标题】:how to force evaluation of macros in a #define for the c-preprocessor如何在 C 预处理器的#define 中强制评估宏
【发布时间】:2016-01-15 19:12:55
【问题描述】:

我想通过使用宏的旧值重新定义宏来改变某些代码的工作方式。但是,由于似乎评估宏的方式,它对我不起作用。我想要的是立即评估#define 中的宏,这样类似

#define A B

将A 定义为B 在#define 时的值,并且不受以后重新定义B 的影响。

这个例子有效:

// in a header somewhere, can't change this
#define A 1


// wrapper code to replace the number with a run-time expression
#define OLD_A 1
#define NEW_A 42
#undef A
bool flag = false;
#define A  ( flag ? NEW_A : OLD_A)


// user code, don't want to change this
//

#include <stdio.h>
main()
{
  flag = false;
  printf("A is %d\n",A);
  flag = true;
  printf("A is %d\n",A);
}

输出(按预期):

1$ ./cpptest
A is 1
A is 42

但是,如果我将OLD_A 的定义更改为A,则它不会编译。

// in a header somewhere, can't change this
#define A 1


// wrapper code to replace the number with a run-time expression
#define OLD_A A  /// <------ here
#define NEW_A 42
#undef A
bool flag = false;
#define A  ( flag ? NEW_A : OLD_A)


// user code, don't want to change this
//

#include <stdio.h>
main()
{
  flag = false;
  printf("A is %d\n",A);
  flag = true;
  printf("A is %d\n",A);
}

构建失败:

$ make cpptest
icpc     cpptest.cpp   -o cpptest
cpptest.cpp(19): error: identifier "A" is undefined
    printf("A is %s\n",A);
                       ^

我知道这是一种将代码设计为可维护的可怕方式,但这是一次性旧版本的补丁,在这种情况下,它对我来说很有意义,因为它需要对其他工作代码进行较少的更改。

【问题讨论】:

    标签: c-preprocessor


    【解决方案1】:

    此答案仅涉及“为什么它不起作用?”问题的一部分。
    关于“如何?”的部分可能需要您放弃使用宏的旧定义的意图;因为我认为这是问题的根源。

    预处理器宏的工作方式与变量不同。
    变量有一个值,并不关心它们是如何得到它的。
    预处理器宏扩展为它们的定义,
    不是定义时定义的值。

    那么在您的问题案例中会发生什么:

    // in a header somewhere, can't change this
    #define A 1
    

    “A”被定义为“1”,稍后会被忽略。

    // wrapper code to replace the number with a run-time expression
    #define OLD_A A  /// <------ here
    

    “OLD_A”被定义为“A”,当前分两步扩展为“1”。

    #define NEW_A 42
    #undef A
    

    “A”未定义,预处理器不再知道它是“1”。

    bool flag = false;
    #define A  ( flag ? NEW_A : OLD_A)
    

    “A”被定义为“(标志?NEW_A:OLD_A)”
    目前将扩展为“(标志?NEW_A:A)”,
    其中“A”(以一种或另一种方式)没有递归扩展(这也无济于事)。

    // user code, don't want to change this
    
    #include <stdio.h>
    main()
    {
      flag = false;
      printf("A is %d\n",A);
    

    编译器看到:'printf("A is %d\n",( flag ? NEW_A : A));'。

      flag = true;
      printf("A is %d\n",A);
    

    编译器看到:'printf("A is %d\n",( flag ? NEW_A : A));'。

    }
    

    您是否尝试仅预处理文件而不是编译?
    它支持我的解释。
    (使用 gcc,在我删除了包含后,本实验不需要它;还从输出中删除了一些无用的行):
    MinGW\bin\gcc -E cpptest.cpp

    bool flag = false;
    
    main()
    {
      flag = false;
      printf("A is %d\n",( flag ? 42 : A));
      flag = true;
      printf("A is %d\n",( flag ? 42 : A));
    }
    

    至少在我看来,您对“糟糕的设计”是正确的。但在现实中,有时优秀的设计会受到外部环境的阻碍。而那些外部情况通常以“€/$/您选择的货币”结尾。
    在这种情况下,情况会绕道“不应更改具有古老且非常好的测试状态的代码”。这是一个很好的理由。
    也许您可以让决策者相信编辑(它将用动态的东西替换当前的完全静态宏“A == 1”)也没有注意到这个要求。测试状态(可能基于代码覆盖率等)在此之后几乎是无效的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-29
      相关资源
      最近更新 更多