Generate Include File Name in a MACro

Generate include file name in a macro

I'd do this using a helper quoting macro. Something like this will give you what you want:

#define QUOTEME(M)       #M
#define INCLUDE_FILE(M) QUOTEME(M##_impl_win.hpp)

#include INCLUDE_FILE(module)

C++ Preprocessor Macros with relation to Include files

The #include directives can't be replaced directly with a macro. However, the entity to be included can be the result of a macro expansion. That is, if you need to use different header names, you can define a macro which expands to what is being included, e.g.:

#define CONCAT(a,b) a ## b
#ifdef USE_C_NAMES
# define MAKE_NAME(x) <x.h>
#else
# define MAKE_NAME(x) <CONCAT(c,x)>
#endif
#include MAKE_NAME(stdio)

Use gcc preprocessor to define filename for #include

You have to escape the ":

gcc -DMY_INCLUDE_FILE=\"some_incfile.h\" main.c

Include macro in a file name

If you want a macro variable to resolve a function, you need %sysfunc. Here's one way to do that.

%let date=%sysfunc(putn(%eval(%sysfunc(today())-3),ddmmyyn6.)); *This is equal to todays date-3 (format = 190317);
%put &=date;

The first %sysfunc asks for the result of today(), the second asks for the result to be formatted. %eval is needed to subtract 3 from the value, as @Quentin points out in comments.

Alternately, call symputx would work here if you're more comfortable in the data step.

data _null_;
call symputx('date',put(today()-3,ddmmyyn6.));
run;
%put &=date;

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.

c macro - how to set a macro name as the output of another macro

In a macro definition, the name part is always a single preprocessor token. However, you can use function-like macros, with parameters, that expand to a single token.

Consider the following macros:

#define  JOIN(a,b)       a ## b

#define FOO(suffix) JOIN(FOO_, suffix)
#define FOOBAZ JOIN(FOO_, BAZ)
#define FOOBAAZ JOIN(foo_, baaz)

#define FOO_BAR first
#define FOO_BAZ second

With the above definitions, declaring

int FOO(BAR) = 1;
int FOOBAZ = 2;
int FOOBAAZ = 3;

is equivalent to (i.e., gets preprocessed to)

int first = 1;
int second = 2;
int foo_baaz = 3;

There are cases (especially when exploring various algorithms) when templates or polymorphic code is useful. Consider for example the following ops.h:

#if defined(TYPE) && defined(PREFIX)
#undef JOIN2
#define JOIN2_(a,b) a ## b
#define JOIN2(a,b) JOIN2_(a, b)
#define NAME(end) JOIN2(PREFIX, end)

static inline TYPE NAME(_add)(const TYPE val1, const TYPE val2)
{
return val1 + val2;
}

static inline TYPE NAME(_sub)(const TYPE val1, const TYPE val2)
{
return val1 - val2;
}

static inline TYPE NAME(_neg)(const TYPE val)
{
return -val;
}

static inline TYPE NAME(_mul)(const TYPE val1, const TYPE val2)
{
return val1 * val2;
}

static inline TYPE NAME(_div)(const TYPE val1, const TYPE val2)
{
return val1 / val2;
}

#endif

#undef NAME
#undef JOIN2
#undef PREFIX
#undef TYPE

The macro NAME(suffix) expands to a single token consisting of the expansion of PREFIX immediately followed by the expansion of suffix. (If they are not preprocessor macros, they are used as-is.) This allows the same header file to be included multiple times, assuming PREFIX is defined to a new value each time.

Note that it is common to have a space between e.g. NAME(_add) and the following (const TYPE val1, const TYPE val2). I omitted it, in the hopes that it makes the function definitions more familiar-looking.

Let's look at an example program using such a header file:

#include <stdlib.h>
#include <inttypes.h>
#include <stdio.h>

#define TYPE uint32_t
#define PREFIX u32
#include "ops.h"

#define TYPE float
#define PREFIX float
#include "ops.h"

#define TYPE double
#define PREFIX dbl
#include "ops.h"

int main(void)
{
printf("dbl_div(217.0, 31.0) = %.1f\n", dbl_div(217.0, 31.0));
printf("u32_sub(4, 2) = %" PRIu32 "\n", u32_sub(4, 2));
printf("float_mul(1.25f, 72.00f) = %.2ff\n", float_mul(1.25f, 72.00f));
return EXIT_SUCCESS;
}

The first #include "ops.h" defines functions u32_add(), u32_sub(), u32_neg(), u32_mul(), and u32_div(). The second defines functions float_add() and so on, and the third dbl_add() and so on.

The above files are valid C99, and when compiled and run, it outputs

dbl_div(217.0, 31.0) = 7.0
u32_sub(4, 2) = 2
float_mul(1.25f, 72.00f) = 90.00f

If you combine the above with suitable macros using C11 _Generic, you can make "functions" that call different implementations based on the type of their argument.



Related Topics



Leave a reply



Submit