如何强制评估c-preprocessor的#define中的宏

时间:2016-01-15 19:12:55

标签: c-preprocessor

我想通过使用宏的旧值重新定义宏来改变某些代码的工作方式。但是,由于宏似乎被评估的方式,它对我不起作用。我想要的是立即评估#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);
                       ^

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

1 个答案:

答案 0 :(得分:0)

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

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

那么在您遇到问题的情况下会发生什么:

// 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)”
目前将扩展为“(flag?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”)也不会听从那个要求。在此之后,测试状态(可能基于代码覆盖率等)将非常无效。

相关问题