#include parameter from a macro expansion

Discussion in 'C Programming' started by pozz, Mar 7, 2012.

  1. pozz

    pozz Guest

    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...
    pozz, Mar 7, 2012
    #1
    1. Advertising

  2. pozz <> writes:

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

    --
    Ben.
    Ben Bacarisse, Mar 7, 2012
    #2
    1. Advertising

  3. pozz <> writes:
    > 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

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Mar 7, 2012
    #3
  4. pozz

    Tim Rentsch Guest

    Keith Thompson <> writes:

    > pozz <> writes:
    >> 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.


    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.
    Tim Rentsch, Mar 8, 2012
    #4
  5. pozz

    Tim Rentsch Guest

    Ben Bacarisse <> writes:

    > pozz <> writes:
    >
    >> 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.


    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.
    Tim Rentsch, Mar 8, 2012
    #5
  6. Tim Rentsch <> writes:

    > Ben Bacarisse <> writes:
    >
    >> pozz <> writes:
    >>
    >>> 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.

    >
    > 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)

    --
    Ben.
    Ben Bacarisse, Mar 8, 2012
    #6
  7. Tim Rentsch <> writes:
    > Ben Bacarisse <> writes:
    >> pozz <> writes:
    >>> 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.

    >
    > 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?

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Mar 8, 2012
    #7
  8. pozz

    Tim Rentsch Guest

    Ben Bacarisse <> writes:

    > Tim Rentsch <> writes:
    >
    >> Ben Bacarisse <> writes:
    >>
    >>> pozz <> writes:
    >>>
    >>>> 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.

    >>
    >> 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)


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

    #define I(x) x
    Tim Rentsch, Mar 9, 2012
    #8
  9. pozz

    Tim Rentsch Guest

    Keith Thompson <> writes:

    > Tim Rentsch <> writes:
    >> Ben Bacarisse <> writes:
    >>> pozz <> writes:
    >>>> 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.

    >>
    >> 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?


    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.
    Tim Rentsch, Mar 9, 2012
    #9
  10. pozz

    James Kuyper Guest

    On 03/10/2012 02:46 AM, pozz wrote:
    > Il 07/03/2012 22:10, Keith Thompson ha scritto:

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

    >
    > 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.
    --
    James Kuyper
    James Kuyper, Mar 11, 2012
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. me
    Replies:
    1
    Views:
    1,122
    Victor Bazarov
    Nov 9, 2004
  2. Benjamin Niemann
    Replies:
    3
    Views:
    326
    Caleb Hattingh
    Aug 26, 2004
  3. Ark

    A question on macro expansion

    Ark, Jul 22, 2004, in forum: C Programming
    Replies:
    3
    Views:
    354
  4. Vittal

    Macro Expansion

    Vittal, Mar 22, 2005, in forum: C Programming
    Replies:
    3
    Views:
    408
    Eric Sosman
    Mar 23, 2005
  5. Dom Gilligan

    Macro expansion of '#__LINE__'?

    Dom Gilligan, Nov 4, 2005, in forum: C Programming
    Replies:
    4
    Views:
    449
    Dom Gilligan
    Nov 4, 2005
Loading...

Share This Page