39

有没有办法定义一个#include 在其主体中包含指令的宏?

如果我只是把“ #include”,它给出了错误

C2162: "expected macro formal parameter"

因为在这里我不用#来连接字符串。
如果我使用“ \# include”,则会收到以下两个错误:

error C2017: illegal escape sequence
error C2121: '#' : invalid character : possibly the result of a macro expansion

有什么帮助吗?

4

9 回答 9

27

所以就像其他人说的那样,不,你不能在宏中包含#include 语句,因为预处理器只执行一次。但是,您可以使用我最近发现自己使用的一个技巧,让预处理器基本上做同样的事情。

意识到预处理器指令不会在宏中做任何事情,但是它们会在文件中做一些事情。因此,您可以将要变异的代码块粘贴到文件中,将其视为宏定义(可以由其他宏更改的部分),然后在各个位置#include 这个伪宏文件(make确保它没有包括警卫!)。它的行为与宏不完全一样,但它可以实现一些非常类似于宏的结果,因为#include 基本上只是将一个文件的内容转储到另一个文件中。

例如,考虑包含许多成组出现的类似名称的标头。将它们全部写出来很乏味,或者甚至它们是自动生成的。您可以通过执行以下操作部分自动化它们的包含:

辅助宏标头:

/* tools.hpp */

#ifndef __TOOLS_HPP__
#def __TOOLS_HPP__

// Macro for adding quotes
#define STRINGIFY(X) STRINGIFY2(X)    
#define STRINGIFY2(X) #X

// Macros for concatenating tokens
#define CAT(X,Y) CAT2(X,Y)
#define CAT2(X,Y) X##Y
#define CAT_2 CAT
#define CAT_3(X,Y,Z) CAT(X,CAT(Y,Z))
#define CAT_4(A,X,Y,Z) CAT(A,CAT_3(X,Y,Z))
// etc...

#endif

伪宏文件

/* pseudomacro.hpp */

#include "tools.hpp"
// NO INCLUDE GUARD ON PURPOSE
// Note especially FOO, which we can #define before #include-ing this file,
// in order to alter which files it will in turn #include.
// FOO fulfils the role of "parameter" in this pseudo-macro.

#define INCLUDE_FILE(HEAD,TAIL) STRINGIFY( CAT_3(HEAD,FOO,TAIL) )

#include INCLUDE_FILE(head1,tail1.hpp) // expands to #head1FOOtail1.hpp
#include INCLUDE_FILE(head2,tail2.hpp)
#include INCLUDE_FILE(head3,tail3.hpp)
#include INCLUDE_FILE(head4,tail4.hpp)
// etc..

#undef INCLUDE_FILE

源文件

/* mainfile.cpp */

// Here we automate the including of groups of similarly named files

#define FOO _groupA_
#include "pseudomacro.hpp"
// "expands" to: 
// #include "head1_groupA_tail1.hpp"
// #include "head2_groupA_tail2.hpp"
// #include "head3_groupA_tail3.hpp"
// #include "head4_groupA_tail4.hpp"
#undef FOO

#define FOO _groupB_
#include "pseudomacro.hpp"
// "expands" to: 
// #include "head1_groupB_tail1.hpp"
// #include "head2_groupB_tail2.hpp"
// #include "head3_groupB_tail3.hpp"
// #include "head4_groupB_tail4.hpp"
#undef FOO

#define FOO _groupC_
#include "pseudomacro.hpp"
#undef FOO

// etc.

这些包含甚至可能位于您想要重复的代码块中间(更改 FOO),正如 Bing Jian 要求的答案:包含 #include 指令的宏定义

我没有广泛使用这个技巧,但它可以完成我的工作。它显然可以根据需要扩展为具有尽可能多的“参数”,并且您可以在其中运行您喜欢的任何预处理器命令,并生成实际代码。您不能将它创建的内容用作另一个宏的输入,就像使用普通宏一样,因为您不能将包含内容粘贴在宏中。但它可以进入另一个伪宏:)。

其他人可能会对其他限制有一些评论,以及可能出什么问题:)。

于 2015-01-07T23:04:15.497 回答
18

我不会争论它的优点,但是 freetype (www.freetype.org) 做了以下事情:

#include FT_FREETYPE_H

他们在其他地方定义 FT_FREETYPE_H

于 2008-11-05T21:10:05.680 回答
7

C 和 C++ 语言明确禁止作为宏扩展的结果形成预处理器指令。这意味着您不能将预处理器指令包含到宏替换列表中。如果你试图通过串联(以及类似的技巧)“构建”一个新的预处理器指令来欺骗预处理器,那么行为是未定义的。

于 2010-08-31T21:23:33.887 回答
6

我相信 C/C++ 预处理器只对代码进行一次传递,所以我认为这行不通。您可能可以通过宏将“#include”放入代码中,但编译器会阻塞它,因为它不知道如何处理它。对于您尝试执行的操作,预处理器必须对文件进行第二次遍历才能获取#include。

于 2008-11-05T20:30:43.500 回答
4

我也想这样做,原因如下:

如果您使用 C 或 C++ 进行编译,某些头文件(尤其是 OpenMPI 中的 mpi.h)的工作方式会有所不同。我正在从我的 C++ 程序链接到 C MPI 代码。要包含标题,我通常会这样做:

extern "C" {
#include "blah.h"
}

但这不起作用,因为__cplusplus即使在 C 链接中仍然定义。这意味着 blah.h 包含的 mpi.h 开始定义模板并且编译器死了,说您不能使用带有 C 链接的模板。

因此,我在 blah.h 中要做的就是替换

#include <mpi.h>

#ifdef __cplusplus
#undef __cplusplus
#include <mpi.h>
#define __cplusplus
#else
#include <mpi.h>
#endif

值得注意的是,不只是 mpi.h 会做这种病态的事情。因此,我想定义一个INCLUDE_AS_C对指定文件执行上述操作的宏。但我想这行不通。

如果有人能想出另一种方法来实现这一点,请告诉我。

于 2010-08-31T21:16:16.107 回答
3

我认为你没问题,因为我也从中得到了这项任务似乎是不可能的

http://groups.google.com/group/comp.lang.c++/browse_thread/thread/03d20d234539a85c#

不,C++(和 C)中的预处理器指令不是反射性的。

帕维尔·齐帕克

无论如何,这种尝试背后的原因是我试图将以下重复使用的代码片段作为宏:

void foo(AbstractClass object)
{
    switch (object.data_type())
    {
    case AbstractClass::TYPE_UCHAR :
        {
        typedef unsigned char PixelType;
        #include "snippets/foo.cpp"
        }
        break;
    case AbstractClass::TYPE_UINT:
        {
        typedef unsigned int PixelType;
        #include "snippets/foo.cpp"
        }
        break;
    default:
        break;
    }
}

对于另一项任务,我需要有类似的功能

void bar(AbstractClass object)

我将放置在哪里

#include "snippets/bar.cpp"

当然,特定于任务的代码是在“snippets/foo.cpp”和“snippets/bar.cpp”中编写的。

于 2008-11-05T21:00:17.450 回答
0

我不知道您实际上要做什么,但看起来您可能想要的是模板化函数。

这样 PixelType 只是代码块的模板参数。

于 2008-11-05T21:16:59.257 回答
0

为什么宏需要有一个#include?如果您要#include'ing 宏所在的任何文件,您可以将#include 与所有其余的#include 语句一起放在宏上方,并且一切都应该很好。

我认为没有理由让宏包含不能仅包含在文件中的任何内容。

于 2008-11-05T20:29:32.423 回答
-8

传染性是正确的——如果你正在做:

我的文件.c:

#include "standardAppDefs.h"
#myStandardIncludeMacro

标准AppDefs.h:

#define myStandardIncludeMacro #include <foo.h>

为什么不直接说:

我的文件.c:

#include "standardAppDefs.h"

标准AppDefs.h:

#include <foo.h>

忘记宏?

于 2008-11-05T20:41:49.217 回答