【问题标题】:C++ conditional macro evaluationC++ 条件宏求值
【发布时间】:2009-03-26 18:48:40
【问题描述】:

我有一个全局定义的符号,需要为我的源文件的给定子集有条件地未定义。所有需要特殊处理的文件都已包含在前包含和后包含中:

pre.h:

#undefine mysymbol // [1]

post.h:

#define mysymbol MY_SYMBOL_DEFINITION // [2]

我的问题是pre.hpost.h 可以被多次包含在给定的源文件由于各种包含链。因此,我需要1 在第一次包含 pre.h 时发生,我需要 2 发生在包含post.h最后一次。从概念上讲:

pre         // undefine
   pre      // no-op
      pre   // no-op
      post  // no-op
   post     // no-op
post        // redefine

由于我使用的是 GCC 3.4.6,我无法访问 push and pop macro pragmas,否则可能会为我解决此问题。

如何使用剩余的预处理器功能模拟该行为?

我试图用预处理器增加/减少一个值,但我不确定这是否可行。

“我真正想做的是什么?”

我们有用new(__FILE__, __LINE__) 替换new 的宏——参见my other question on this topic——我们需要取消定义由上述前置和后置包含的源文件集中的这些宏,因为我们是无法创建与其中使用的放置新语法兼容的宏。

【问题讨论】:

  • 显而易见的问题是“你到底想做什么?”
  • @Neil -- 已添加,请参阅编辑

标签: c++ gcc macros c-preprocessor


【解决方案1】:

您可以将这样的内容添加到您的 pre.h 文件中:

... 

#ifdef COUNT
#if COUNT == 2
#undef COUNT
#define COUNT 3
#endif

#if COUNT == 1
#undef COUNT
#define COUNT 2
#endif

#else
#define COUNT 1

... here put your pre.h code

#endif

在 post.h 中:

#ifdef COUNT
#if COUNT == 1
#undef COUNT
#endif

#if COUNT == 2
#undef COUNT
#define COUNT 1
#endif

#if COUNT == 3
#undef COUNT
#define COUNT 2
#endif

...    

#end

#ifndef COUNT

... here put your pre.h code

#endif

但你需要知道你能走多远。

【讨论】:

  • 你和 Ben Murphy 有相似的想法 :-)
【解决方案2】:

如果您知道递归的最大深度,那么您应该能够通过在每个级别定义一个新宏来模拟推送/弹出。对于您给出的 3 级示例,它看起来像:

Pre.h:

#ifdef RECURSION_COUNT_1
 #ifdef RECURSION_COUNT_2
  #ifdef RECURSION_COUNT_3
   #error Recursion level too deep
  #else
   #define RECURSION_COUNT_3
  #endif
 #else
  #define RECURSION_COUNT_2
 #endif
#else
 #define RECURSION_COUNT_1
 #undef YOUR_SYMBOL_HERE
#endif

Post.h

#ifdef RECURSION_COUNT_3
 #undef RECURSION_COUNT_3
#else
 #ifdef RECURSION_COUNT_2
  #undef RECURSION_COUNT_2
 #else
  #ifdef RECURSION_COUNT_1
   #undef RECURSION_COUNT_1
   #define YOUR_SYMBOL_HERE
  #endif
 #endif
#endif

【讨论】:

  • 有趣的解决方案,如果有点冗长:-)
  • 嗯,一次只定义这些宏中的一个会更简洁 - 然后该命令可以像 klew 的解决方案一样处理 else 分支。
【解决方案3】:

pre.h

#ifndef MYSYMBOLUNDEFFERSTACK
#define MYSYMBOLUNDEFFERSTACK 0
#else
#define MYSYMBOLUNDEFFERSTACKTMP (MYSYMBOLUNDEFFERSTACK+1)
#undef MYSYMBOLUNDEFFERSTACK
#define MYSYMBOLUNDEFFERSTACK MYSYMBOLUNDEFFERSTACKTMP
#undef MYSYMBOLUNDEFFERSTACKTMP
#endif

#if MYSYMBOLUNDEFFERSTACK == 0
#undef mysymbol
#endif

post.h

#ifndef MYSYMBOLUNDEFFERSTACK
#error "Async Post.h"
#else
#define MYSYMBOLUNDEFFERSTACKTMP (MYSYMBOLUNDEFFERSTACK-1)
#undef MYSYMBOLUNDEFFERSTACK
#define MYSYMBOLUNDEFFERSTACK MYSYMBOLUNDEFFERSTACKTMP
#undef MYSYMBOLUNDEFFERSTACKTMP
#endif

#if MYSYMBOLUNDEFFERSTACK == 0
#define mysymbol "MY_SYMBOL_DEFINITION"
#endif

在这种情况下效果很好:

#include "stdio.h"
#include "pre.h"
#include "pre.h"
#include "pre.h"
//const char *pCompileError = mysymbol;
#include "post.h"
//const char *pCompileError = mysymbol;
#include "post.h"
//const char *pCompileError = mysymbol;
#include "post.h"

int main(void)
{
    const char *p = mysymbol;
    printf("%s\n", p);
    return 0;
}

编辑: 适用于 gcc 4.0。

【讨论】:

  • 这实际上不起作用——符号是在第一次包含 post.h 之后定义的。请尝试看看。
  • 预处理器中的数值评估有些陈旧。否则,“#ifdef”就不需要“#if”。我经常看到像“#if DEFINEDVALUE >= 2”这样的代码。可能是您的 gcc 版本中的错误?
  • @nusi -- 我的意思是,如果你有“#define A 1”和“#define B (A+1)”,这不会导致 B==2上面的代码。
  • "#define A 1, #define B (A+1), #if B == 2, #error foo, #endif" 适用于 gcc4。但你是对的,我答案中的代码似乎有缺陷。
  • @nusi -- 是的,你是对的,简单的案例有效。但是通过“temp”传递值是行不通的。有什么想法吗?
【解决方案4】:

使用元编程魔法 a-la Loki 可能可以在编译时增加/减少一个值。但是你确定这是必要的吗?

为什么你的 h 文件被包含这么多次?为什么不使用包含防护?

【讨论】:

  • pre/post 标头的重点是包装它们包含的每个文件。包含守卫将打破这种行为,因为每个编译单元只会包含一次 pre/post。
【解决方案5】:

试试:

文件 pre.h

#ifndef MYMACROGUARD
    #undef MYMACRO
    #define MYMACROGUARD MYMACROGUARD+1
#endif

文件 post.h

#if MYMACROGUARD <= 0
    #undef MYMACROGUARD
#else
    #define MYMACROGUARD MYMACROGUARD-1
#endif

用这段代码测试过

#define MYMACRO

#include<iostream>

using namespace std;
int main()
{
    #ifdef MYMACRO
        cout<<"1"<<endl;
    #endif

    #include <pre.h>

    #ifdef MYMACRO
        cout<<"2"<<endl;
    #endif

    #include <pre.h>

    #ifdef MYMACRO
        cout<<"3"<<endl;
    #endif

    #include <post.h>

    #ifdef MYMACRO
        cout<<"4"<<endl;
    #endif

    #include <post.h>

    #ifdef MYMACRO
        cout<<"5"<<endl;
    #endif
}

$> g++ -w -I. test.cpp && ./a.out

1
5

【讨论】:

  • 我已经尝试过了,但预处理器中似乎没有进行数值评估。你也不能重新定义守卫。最后,宏本身(MYMACROGUARD)不会在替换文本中被替换。
  • 这对你有用是巧合,因为你只有两层嵌套。如果你尝试了三层嵌套,它会失败。
  • 我已经尝试过 gcc 和 g++,但我无法让 #define SOME SOME+1 工作。它重新定义宏而不添加。当我尝试在我的代码中使用 SOME 时,它会扩展到 SOME+1。并且使用 #if
  • 我在 codepad.org 中尝试过(他们似乎使用 g++) - 抱怨宏重新定义。
猜你喜欢
  • 2022-01-10
  • 2017-06-03
  • 1970-01-01
  • 1970-01-01
  • 2017-04-18
  • 1970-01-01
  • 2019-09-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多