43

Is there a way to define a macro that contains a #include directive in its body?

If I just put the "#include", it gives the error

C2162: "expected macro formal parameter"

since here I am not using # to concatenate strings.
If I use "\# include", then I receive the following two errors:

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

Any help?

ThatsJustCheesy
  • 1,370
  • 14
  • 24
Bing Jian
  • 994
  • 3
  • 10
  • 18

9 Answers9

30

So like the others say, no, you can't have #include statements inside a macro, since the preprocessor only does one pass. However, you can make the preprocessor do basically the same thing with a gnarly trick I found myself using recently.

Realise that preprocessor directives won't do anything inside a macro, however they WILL do something in a file. So, you can stick a block of code you want to mutate into a file, thinking of it like a macro definition (with pieces that can be altered by other macros), and then #include this pseudo-macro file in various places (make sure it has no include guards!). It doesn't behave exactly like a macro would, but it can achieve some pretty macro-like results, since #include basically just dumps the contents of one file into another.

For example, consider including lots of similarly named headers that come in groups. It is tedious to write them all out, or perhaps even they are auto-generated. You can partially automate their inclusion by doing something like this:

Helper macros header:

/* 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

Pseudo-macro file

/* 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

Source 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.

These includes could even be in the middle of codes blocks you want to repeat (with FOO altered), as the answer by Bing Jian requests: macro definition containing #include directive

I haven't used this trick extensively, but it gets my job done. It can obviously be extended to have as many "parameters" as needed, and you can run whatever preprocessor commands you like in there, plus generate actual code. You just can't use the stuff it creates as the input into another macro, like you can with normal macros, since you can't stick the include inside a macro. But it can go inside another pseudo-macro :).

Others might have some comments on other limitations, and what could go wrong :).

Community
  • 1
  • 1
Ben Farmer
  • 2,387
  • 1
  • 25
  • 44
  • 2
    Sounds great, but in theory it is not defined in the standard, and it is dependent on the compiler implementation. See http://stackoverflow.com/questions/20524491/preprocessor-concatenation-for-include-path/20524959#20524959 – Antonio Aug 24 '16 at 13:02
  • Wonderous. What I would really like to do is put a #define in the include, so that I can have macros that define macros. Things like the Openssl STACK_OF would benefit from this. This should have been in the C standard long ago, but the "macros are evil" lobby seems to have won. So we use Perl instead, hardly less evil. – Tuntable May 19 '17 at 01:01
  • 1
    Hmm, you can can't you? You can define whatever you like in the included file and it should work like normal. – Ben Farmer May 19 '17 at 05:40
19

I will not argue the merits for it, but freetype (www.freetype.org) does the following:

#include FT_FREETYPE_H

where they define FT_FREETYPE_H elsewhere

Dan Hewett
  • 2,200
  • 1
  • 14
  • 18
  • 11
    That is explicitly permitted in the standards, and hence is portable as long as FT_FREETYPE_H expands to either the or the "header.h" form. – Jonathan Leffler Nov 05 '08 at 22:42
  • +1 since this avoids depending on implementation-defined behavior - even if it does mean being very trusting of your build system. – einpoklum Mar 10 '17 at 21:27
8

C and C++ languages explicitly prohibit forming preprocessor directives as the result of macro expansion. This means that you can't include a preprocessor directive into a macro replacement list. And if you try to trick the preprocessor by "building" a new preprocessor directive through concatenation (and tricks like that), the behavior is undefined.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
7

I believe the C/C++ preprocessor only does a single pass over the code, so I don't think that would work. You might be able to get a "#include" to be placed in the code by the macro, but the compiler would choke on it, since it doesn't know what to do with that. For what you're trying to do to work the preprocessor would have to do a second pass over the file in order to pick up the #include.

Herms
  • 37,540
  • 12
  • 78
  • 101
4

I also wanted to do this, and here's the reason:

Some header files (notably mpi.h in OpenMPI) work differently if you are compiling in C or C++. I'm linking to a C MPI code from my C++ program. To include the header, I do the usual:

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

But this doesn't work because __cplusplus is still defined even in C linkage. That means mpi.h, which is included by blah.h, starts defining templates and the compiler dies saying you can't use templates with C linkage.

Hence, what I have to do in blah.h is to replace

#include <mpi.h>

with

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

Remarkably it's not just mpi.h that does this pathological thing. Hence, I want to define a macro INCLUDE_AS_C which does the above for the specified file. But I guess that doesn't work.

If anyone can figure out another way of accomplishing this, please let me know.

Lutorm
  • 381
  • 2
  • 7
  • The pseudo-macros I describe in my answer would let you do this :). The syntax isn't as nice as a regular macro would be, but it would work :). You'd end up with something like "#define FILENAME ", "#include include_as_c.hpp", "#undef FILENAME", with your special way of including occurring inside include_as_c.hpp. http://stackoverflow.com/questions/266501/macro-definition-containing-include-directive/27830271#27830271 – Ben Farmer Jan 07 '15 at 23:37
3

I think you are all right in that this task seems impossible as I also got from

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

No, preprocessor directives in C++ (and C) are not reflective.

Pawel Dziepak

Anyway, the reason behind this attempt is that I am trying to make the following repeatedly used code snippet as a macro:

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;
    }
}

For another task, I need to have a similar function

void bar(AbstractClass object)

where I will place

#include "snippets/bar.cpp"

and of course it is in "snippets/foo.cpp" and "snippets/bar.cpp" that the task-specific code is written.

Bing Jian
  • 994
  • 3
  • 10
  • 18
  • 2
    You should probably look at templates (as stbuton suggested). You should certainly be looking to avoid needing to do that. – Jonathan Leffler Nov 05 '08 at 22:42
  • as a general rule, you should probably put all your #include statements in the same place (usually the top). it makes maintaining and debugging your code ALOT simpler. – helloandre Nov 06 '08 at 01:30
  • I have a slightly crazy way of doing basically what you want (using the preprocessor); see my answer :) http://stackoverflow.com/a/27830271/1447953 – Ben Farmer Jan 07 '15 at 23:17
0

I have no idea what you are actually trying to do but it looks like what you might want is a templated function.

That way the PixelType is just a template parameter to the block of code.

user21714
  • 5,781
  • 1
  • 20
  • 26
-2

Why would the macro need to have an #include? if you're #include'ing whatever file the macro is in, you could just put the #include above the macro with all the rest of the #include statements, and everything should be nice and dandy.

I see no reason to have the macro include anything that couldn't just be included in the file.

helloandre
  • 10,541
  • 8
  • 47
  • 64
-9

Contagious is right -- if you're doing:

myFile.c:

#include "standardAppDefs.h"
#myStandardIncludeMacro

standardAppDefs.h:

#define myStandardIncludeMacro #include <foo.h>

Why not just say:

myFile.c:

#include "standardAppDefs.h"

standardAppDefs.h:

#include <foo.h>

And forget the macros?

HanClinto
  • 9,423
  • 3
  • 30
  • 31