Macro Definition Containing #Include Directive

How to use a macro in an #include directive?

You can use a series of macros to create your include file. Unfortunately, I can't think of any cleaner (in-source) way of doing this. This works for arm-eabi-none-gcc v5.4.1.

#define LIBC_DIR ../../../../lib/libc++/

#define STRINGIFY_MACRO(x) STR(x)
#define STR(x) #x
#define EXPAND(x) x
#define CONCAT(n1, n2) STRINGIFY_MACRO(EXPAND(n1)EXPAND(n2))
#define CONCAT5(n1, n2, n3, n4, n5) STRINGIFY_MACRO(EXPAND(n1)EXPAND(n2)EXPAND(n3)EXPAND(n4)EXPAND(n5))

// Concatenate the five elements of your path.
// Of course, this can be simplified if there is only a prefix and a suffix
// that needs to be added and the ARCH_FAMILY, /, and ARCH are always present
// in the macro-generated #include directives.
#include CONCAT5(LIBC_DIR,ARCH_FAMILY,/,ARCH,/stkl/printkc/printkc.h)

Construct path for #include directive with macro

I tend to agree with the comment in utnapistim's answer that you shouldn't do this even though you can. But, in fact, you can, with standard-conformant C compilers. [Note 1]

There are two issues to overcome. The first one is that you cannot use the ## operator to create something which is not a valid preprocessor token, and pathnames do not qualify as valid preprocessor tokens because they include / and . characters. (The . would be ok if the token started with a digit, but the / will never work.)

You don't actually need to concatenate tokens in order to stringify them with the # operator, since that operator will stringify an entire macro argument, and the argument may consist of multiple tokens. However, stringify respects whitespace [Note 2], so STRINGIFY(Dir File) won't work; it will result in "directory/ filename.h" and the extraneous space in the filename will cause the #include to fail. So you need to concate Dir and File without any whitespace.

The following solves the second problem by using a function-like macro which just returns its argument:

#define IDENT(x) x
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define PATH(x,y) STR(IDENT(x)IDENT(y))

#define Dir sys/
#define File socket.h

#include PATH(Dir,File)

Warning: (Thanks to @jed for passing on this issue.) If the strings being concatenated contain identifiers which are defined elsewhere as macros, then unexpected macro substitution will occur here. Caution should be taken to avoid this scenario, particularly if Dir and/or File are not controlled (for example, by being defined as a command-line parameter in the compiler invocation).

You need to also be aware than some implementations may define words which are likely to show up in a token-like fashion in a file path. For example, GCC may define macros with names like unix and linux unless it is invoked with an explicit C standard (which is not the default). That could be triggered by paths like platform/linux/my-header.h or even linux-specific/my-header.h.

To avoid these issues, I'd recommend that if you use this hack:

  • you use a C (or C11) standards-conformant compiler setting, and

  • you place the sequence very early in your source file, ideally before including any other header, or at least any header outside of the standard library.

Also, you wouldn't need the complication of the IDENT macro if you could write the concatenation without spaces. For example:

#define XSTR(x) #x
#define STR(x) XSTR(x)

#define Dir sys
#define File socket.h

#include STR(Dir/File)


Notes

  1. I tried it with clang, gcc and icc, as available on godbolt. I don't know if it works with Visual Studio.

  2. More accurately, it semi-respects whitespace: whitespace is converted to a single space character.

Wrapping #include directive into macro

Change the contents of your include file to :

#define BIG_LIST_INC ...

where ... is the current content of the file (if it spans multiple lines, don't forget to end lines with \).

Then include the file at the top of your source file, and the big list can be inserted in the code using BIG_LIST_INC :

#include "big_list.h"

// <code>
BIG_LIST_INC
// <more_code>

How do I use a preprocessor macro inside an include?

Is this valid C/C++?

The usage is valid C, provided that the macro definition is in scope at the point where the #include directive appears. Specifically, paragraph 6.10.2/4 of C11 says

A preprocessing directive of the form

# include pp-tokens new-line

(that does not match one of the two previous forms) is permitted. The
preprocessing tokens after include in the directive are processed just
as in normal text. (Each identifier currently defined as a macro name
is replaced by its replacement list of preprocessing tokens.
) The
directive resulting after all replacements shall match one of the two
previous forms.

(Emphasis added.) Inasmuch as the preprocessor has the same semantics in C++ as in C, to the best of my knowledge, the usage is also valid in C++.

What is the rationale behind these macros?

I presume it is intended to provide for indirection of the header name or location (by providing alternative definitions of the macro).

How can I convince Clang to parse these headers?

Provided, again, that the macro definition is in scope at the point where the #include directive appears, you shouldn't have to do anything. If indeed it is, then Clang is buggy in this regard. In that case, after filing a bug report (if this issue is not already known), you probably need to expand the troublesome macro references manually.

But before you do that, be sure that the macro definitions really are in scope. In particular, they may be guarded by conditional compilation directives -- in that case, the best course of action would probably be to provide whatever macro definition is needed (via the compiler command line) to satisfy the condition. If you are expected to do this manually, then surely the build documentation discusses it. Read the build instructions.

Expand define macro with include macro

This can't be done.

The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one, [...]

That particular quote is from a reasonably recent draft of the C++ standard, but with minor changes in wording, the same basic idea has been around nearly forever.

Is there a way to define a preprocessor macro that includes preprocessor directives?

You cannot define preprocessing directives the way you show in the question.

Yet you may be able to use the _Pragma operator for your purpose:

#if defined __GNUC__ && __GNUC__ >= 8
#define foo _Pragma("GCC unroll 128") _Pragma("GCC ivdep")
#elif defined __clang__
#define foo _Pragma("clang loop vectorize(enable) interleave(enable)")
#else
#define foo
#endif

Macro substitution in #include directive

String literal concatenation happens two translation phases after #include-directives are resolved; your approach cannot work. Instead, try something along the lines of

#define STRINGIZE_(a) #a
#define STRINGIZE(a) STRINGIZE_(a)

#define MYFILE stdio
#include STRINGIZE(MYFILE.h)

int main() {
printf("asdf");
}

Demo.

Can I define a macro in a header file?

Yes, it would work. (Disregarding the problem with underscores that others have pointed out.)

Directive #include "MyClass.h" just copies the whole content of file MyClass.h and pastes it in the place of the #include. From the point of view of the compiler there is only one source file composed of the file specified by the user and all included files.


Having said that, it would be much better if you use in-language construction instead of preprocessor directive.
For example replace:

#define _BufferSize_ 64

with

constexpr size_t BufferSize = 64;

The only thing it does differently than the #define is that it specifies the type of the value (size_t in this case). Beside that, the second code will behave the same way and it avoids disadvantages of preprocessor.

In general, try to avoid using preprocessor directives. This is an old mechanism that was used when c++ coudn't do that things in-language yet.



Related Topics



Leave a reply



Submit