#include parameter from a macro expansion

P

pozz

In a C file I want to include a file depending on the macro NAME. For
example, if it is "foo", the file to include will be "foo
\foo_params.h". If it is bar, the include file will be "bar
\bar_params.h".

I tried to achieve this, but without success. I started from:

#define INCLUDE_FILE "foo\foo_params.h"
#include INCLUDE_FILE

and it worked. After that I tried the following:

#define INCLUDE_FILE "foo\foo" ## "_params.h"
#include INCLUDE_FILE

without success...
 
B

Ben Bacarisse

pozz said:
In a C file I want to include a file depending on the macro NAME. For
example, if it is "foo", the file to include will be "foo
\foo_params.h". If it is bar, the include file will be "bar
\bar_params.h".

I tried to achieve this, but without success. I started from:

#define INCLUDE_FILE "foo\foo_params.h"
#include INCLUDE_FILE

and it worked. After that I tried the following:

#define INCLUDE_FILE "foo\foo" ## "_params.h"
#include INCLUDE_FILE

without success...

## is token pasting and two strings can't be pasted into a valid token.

I am not sure yu can do exactly what you want, maninly because of the
'_' character. Change that to something that can't be part of a macro
name, and you can do this:

#define NAME foo
#define STR(a) #a
#define XSTR(a) STR(a)
#define INCLUDE_FILE XSTR(NAME/NAME-params.h)
#include INCLUDE_FILE

Maybe some PP expert can remove the restriction on the separator.
 
K

Keith Thompson

pozz said:
In a C file I want to include a file depending on the macro NAME. For
example, if it is "foo", the file to include will be "foo
\foo_params.h". If it is bar, the include file will be "bar
\bar_params.h".

I tried to achieve this, but without success. I started from:

#define INCLUDE_FILE "foo\foo_params.h"
#include INCLUDE_FILE

and it worked. After that I tried the following:

#define INCLUDE_FILE "foo\foo" ## "_params.h"
#include INCLUDE_FILE

without success...

You *probably* don't want a backslash character in your #include
directive.

If you had a string literal "foo\foo_params.h", the \f sequence would be
replaced by a form feed character.

But in

#include "foo\foo_params.h"

that thing that *looks* like a string literal is really a
"q-char-sequence" enclosed in quotation marks (see section 6.10.2
of the C standard). The rules for how the characters between the quotes
are interpreted are implementation-defined.

Normally on Windows, you'd use a forward slash to denote a directory
delimiter; Windows actually permits both / and \ characters, and the
compiler might do some translation as well.

There are three forms of #include directive:

# include <h-char-sequence> new-line

# include "q-char-sequence" new-line

# include pp-tokens new-line

where the third form must, after preprocessing, match one of the first
two forms. But (C11 6.10.2p4):

The method by which a sequence of preprocessing tokens between
a < and a > preprocessing token pair or a pair of " characters
is combined into a single header name preprocessing token is
implementation-defined.

And there's a footnote:

Note that adjacent string literals are not concatenated into a
single string literal (see the translation phases in 5.1.1.2); thus,
an expansion that results in two string literals is an invalid
directive.

I don't see portable, or even non-portable, way to do what you're
trying to do. If there's a solution that I'm missing, it probably
involves token-pasting with the ## operator.

If you have a finite set of "foo" and "bar" values, you can use a more
brute-force approach:

#if FOO
#include "foo/foo_params.h"
#elif BAR
#include "bar/bar_params.h"
#elif
...
#endif
 
T

Tim Rentsch

Keith Thompson said:
You *probably* don't want a backslash character in your #include
directive.

If you had a string literal "foo\foo_params.h", the \f sequence would be
replaced by a form feed character.

But in

#include "foo\foo_params.h"

that thing that *looks* like a string literal is really a
"q-char-sequence" enclosed in quotation marks (see section 6.10.2
of the C standard). The rules for how the characters between the quotes
are interpreted are implementation-defined.

More pointedly, _any_ use of \ inside a {h,q}-char-sequence is
undefined behavior. Presumably though it works okay on his
system (though he probably still should use / rather than \).

Normally on Windows, you'd use a forward slash to denote a directory
delimiter; Windows actually permits both / and \ characters, and the
compiler might do some translation as well.

There are three forms of #include directive:

# include <h-char-sequence> new-line

# include "q-char-sequence" new-line

# include pp-tokens new-line

where the third form must, after preprocessing, match one of the first
two forms. But (C11 6.10.2p4):

The method by which a sequence of preprocessing tokens between
a < and a > preprocessing token pair or a pair of " characters
is combined into a single header name preprocessing token is
implementation-defined.

This matters only if there are several preprocessing tokens that
need to be combined, which isn't necessary to solve this problem.

And there's a footnote:

Note that adjacent string literals are not concatenated into a
single string literal (see the translation phases in 5.1.1.2); thus,
an expansion that results in two string literals is an invalid
directive.

I don't see portable, or even non-portable, way to do what you're
trying to do. If there's a solution that I'm missing, it probably
involves token-pasting with the ## operator. [snip alternative]

Hmm. I didn't think this problem was that hard. No ## operator
needed.
 
T

Tim Rentsch

Ben Bacarisse said:
## is token pasting and two strings can't be pasted into a valid token.

I am not sure yu can do exactly what you want, maninly because of the
'_' character. Change that to something that can't be part of a macro
name, and you can do this:

#define NAME foo
#define STR(a) #a
#define XSTR(a) STR(a)
#define INCLUDE_FILE XSTR(NAME/NAME-params.h)
#include INCLUDE_FILE

Maybe some PP expert can remove the restriction on the separator.

I've commented else-thread about \ and /. Keeping with use of
the / character, here is:

#define HEADER_FOR(name) XSTR( DOUBLE_UP(name)_params.h )
#define DOUBLE_UP(name) name/name
// ... XSTR and STR as above ...

#include HEADER_FOR(foo)

AFAIK guaranteed completely portable.
 
B

Ben Bacarisse

Tim Rentsch said:
I've commented else-thread about \ and /. Keeping with use of
the / character, here is:

#define HEADER_FOR(name) XSTR( DOUBLE_UP(name)_params.h )
#define DOUBLE_UP(name) name/name
// ... XSTR and STR as above ...

#include HEADER_FOR(foo)

AFAIK guaranteed completely portable.

Of course! That's great.

There's a more general point here: any macro invocation can stop the _
being taken as part of the previous token. To re-work my example:

#define ID(x) x
#include XSTR(NAME/ID(NAME)_params.h)
 
K

Keith Thompson

Tim Rentsch said:
I've commented else-thread about \ and /. Keeping with use of
the / character, here is:

#define HEADER_FOR(name) XSTR( DOUBLE_UP(name)_params.h )
#define DOUBLE_UP(name) name/name
// ... XSTR and STR as above ...

#include HEADER_FOR(foo)

AFAIK guaranteed completely portable.

Nice. I can verify that it works with gcc and the Solaris 9
C compiler.

I have one nagging doubt about your solution, specifically about

#define DOUBLE_UP(name) name/name

N1570 6.10.3 says that a macro invocation expands to a list of
preprocessing tokens. What prevents the preprocessor from inserting
white space before or after the / pp-token?

In other words, if an implementation expanded

#include INCLUDE_FILE

to

#include "foo / foo_params.h"

what clause of the Standard would it violate?
 
T

Tim Rentsch

Ben Bacarisse said:
Of course! That's great.

There's a more general point here: any macro invocation can stop the _
being taken as part of the previous token. To re-work my example:

#define ID(x) x
#include XSTR(NAME/ID(NAME)_params.h)

I have to laugh because my first solution to the problem
included the following macro definition

#define I(x) x
 
T

Tim Rentsch

Keith Thompson said:
Nice. I can verify that it works with gcc and the Solaris 9
C compiler.

I have one nagging doubt about your solution, specifically about

#define DOUBLE_UP(name) name/name

N1570 6.10.3 says that a macro invocation expands to a list of
preprocessing tokens. What prevents the preprocessor from inserting
white space before or after the / pp-token?

In other words, if an implementation expanded

#include INCLUDE_FILE

to

#include "foo / foo_params.h"

what clause of the Standard would it violate?

If you re-read 5.1.1.2p1 (specifically #3 and #7), 6.4p3, 6.10.3p1,
6.10.3p7, and 6.10.3.2p2, do you still have doubts? I don't.
 
J

James Kuyper

Il 07/03/2012 22:10, Keith Thompson ha scritto: ....

Really? So one of the most used preprocessing directive (#include) has
an implementation-behaviour...

How could it not be? The naming conventions for directories and files
are wildly different on different operating systems, and in many cases
those conventions would make it extremely inconvenient to create a C
string literal that corresponds to what unix-like systems call a valid
path name (which might be called something wildly different on other
systems). The C standard copes with that wide variety by leaving the
interpretation implementation-defined.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top