【问题标题】:Wrap function call with macro [duplicate]用宏包装函数调用[重复]
【发布时间】:2018-02-08 16:50:26
【问题描述】:

是否可以只用宏包装函数调用?

当我尝试时

#define foo(x) bar(x)

它包装了函数调用和定义。

我知道用链接器包装函数,但在这种情况下我不能使用这个解决方案。

让我们假设一些代码

#define foo(x) bar(z)

int foo(int z){
//some code
}

int bar(int x){
//some code
}

int function(){
int a = foo(2);
}

我想 int a = foo(2);预处理后变为 int a = bar(2)。 目前我只收到“重新定义”错误。

编辑:我的示例显示了我想要实现的目标,但是在实际代码中我必须通过 cmake 文件将此宏放入项目中,并且我也无法修改目标文件中的源代码。很抱歉之前没有提及。

【问题讨论】:

  • it wraps both function call and definition -- 什么?它所做的只是用bar(x) 替换字符串foo(x)。预处理器不处理定义,那是在编译阶段。
  • 您能更具体地说明您想要实现的目标吗?
  • 如果你想在某个地方禁止宏扩展,你只需要将宏放在括号中,例如int (foo)(void)
  • 预处理器处理文本,它对 C 语法或语义一无所知。当它看到foo 后跟括号时,它会替换它。
  • @JensGustedt looking at question history,我猜这是为了使用外部单元测试文件中定义的备用存根来隐藏函数调用?对吗?

标签: c c-preprocessor


【解决方案1】:

使用 undef 来管理宏的生命周期,而不是搞乱不知道宏存在的代码部分。

int foo(int z){
//some code
}

int bar(int x){
//some code
}

int function(){
    #define foo(x) bar(z)
    int a = foo(2);
    #undef foo
}

这个技巧扩展到诸如头选项之类的东西,通常包括 Windows.h 之类的东西,并且头的定义取决于在头之外定义的定义,如下所示:

#define WIN32_LEAN_AND_MEAN // used in ifdef checks to not define/include rarely used stuff
#define NO_STRICT // used to allow HANDLE types to be used as void * without type errors
#define NO_MINMAX // used to avoid errors because MIN/MAX are already defined
#include <Windows.h>

这会用在标头完成解析后没有用的宏污染范围,因此您可以通过在包含后取消定义它们来清理:

#define WIN32_LEAN_AND_MEAN // used in ifdef checks to not define/include rarely used stuff
#define NO_STRICT // used to allow HANDLE types to be used as void * without type errors
#define NO_MINMAX // used to avoid errors because MIN/MAX are already defined
#include <Windows.h>
#undef NO_MINMAX 
#undef NO_STRICT 
#undef WIN32_LEAN_AND_MEAN

这使阅读您的代码的人,尤其是 C 初学者更容易知道这些是选项,并且在包含发生后没有任何用处。这还允许您执行有趣的类似 C++ 的行为,例如基于包含之前定义的定义的模板,而不会多次包含标头冲突。

【讨论】:

  • 如果foo 有一个#define,通常#define foo(x) bar(z) 会受益于预先测试。
  • 非天真地,您应该 #ifdef 每个您 #define 的宏,但这会带来奇怪的烦恼,例如如果该宏已定义,那么您必须创建另一个宏来跟踪以下事实您正在重新定义宏,并且可能需要将其重新定义回之前的状态。避免这种情况的一种方法是生成一个 guid 并将“-”替换为下划线并在 guid 前面加上 _,这样实际上不太可能发生冲突,但这会牺牲短宏的好处;我喜欢假设如果我的宏短于 3 个字符,那么除了我之外没有人应该使用它。
  • 这就是为什么 undef 很重要;许多标头定义了许多短宏,例如 MIN 和 MAX 或 N,它们是理想的宏名称;几乎没有使用长度小于 3 个字符的小写宏,因此 foo/bar/baz/a/b/c 应该是真正安全的短期范围宏。您应该在定义之前测试#ifdef 宏,如果是,如果它正在使用中,则取消定义它。一个恼人的罪魁祸首是 CreateWindow。您可能想在类中创建一个方法 CreateWindow,但 Windows.h 根据是否定义了 unicode 来定义它。在这种情况下,我取消定义 CreateWindow。
【解决方案2】:

不确定这是否是您想要的,但您可以尝试将宏放在函数声明之后。所以

foo(...){}
bar(...){}
#ifdef REPLACE_FOO
#define foo(x) bar(x)
#endif
main(){
    foo(1);
}

【讨论】:

  • 我忘记了这样的解决方案。我必须在 cmake 文件中定义宏,所以它的范围是整个项目。
  • 我编辑的解决方案会起作用吗?
  • 我编辑了我的帖子,提供了更多细节。
【解决方案3】:

这是因为预处理器并不关心替换哪个字符串。 它还替换了你原来的函数定义foo,这意味着函数bar被定义了两次。

你应该可以通过这样的方式解决这个问题:

#if !defined(foo)
int foo(int z){
   //some code
}
#endif

当然,这取决于你真正想做什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-11
    • 2015-06-09
    • 2014-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多