basic help with counting?

Discussion in 'C Programming' started by Ark, Nov 19, 2011.

  1. Ark

    Ark Guest

    Hello NG,
    I want a macro to count the number of tokens in a comma-separated list.
    I want it to yield a constant integer expression.

    I do something like
    #define VERBATIM(...) __VA_ARGS__ //not quite verbatim but OK
    #define COUNT(...) \
    VERBATIM(sizeof(struct {char VERBATIM(__VA_ARGS__);}))
    #define COUNT1(...) \
    offsetof(VERBATIM(struct {char VERBATIM(__VA_ARGS__), endmark;}), endmark)

    [Of course, VERBATIM is used to package multi-token argument as one
    macro parameter.]

    The evaluation compiles fine:
    const int x = COUNT(a, b, c);

    However the conditional fails:
    #if COUNT(a, b, c) != 3
    ....

    Here are IAR EWARM 5.30 errors
    Error[Pe193]: zero used for undefined preprocessing identifier count.c 13
    Error[Pe059]: function call is not allowed in a constant expression
    count.c 13
    Error[Pe193]: zero used for undefined preprocessing identifier count.c 13
    Error[Pe018]: expected a ")" count.c 13

    And even more errors with
    #if COUNT1(a, b, c) != 3
    ....

    IOW, neither COUNT nor COUNT1 yield a constant integer expression wanted
    by #if. Compiler diagnostic is less than helpful.
    What am I doing wrong?

    Another question:
    Is there a trick to make COUNT() and/or COUNT1() yield 0?

    --
    Thanks - Ark
    Ark, Nov 19, 2011
    #1
    1. Advertising

  2. Ark

    Kaz Kylheku Guest

    On 2011-11-19, Ark <> wrote:
    > However the conditional fails:
    > #if COUNT(a, b, c) != 3


    The preprocessing stages in C (a.k.a. "the preprocessor") do not know
    anything about types.

    Stuff like:

    #if sizeof (struct foo) != 3

    is impossible. Preprocessor expressions are just integer math, e.g:

    #if PROGRAM_VERSION > 3

    If PROGRAM_VERSION is not defined, it is replaced with 0.
    Kaz Kylheku, Nov 20, 2011
    #2
    1. Advertising

  3. Ark <> writes:
    <snip>
    > I want a macro to count the number of tokens in a comma-separated
    > list. I want it to yield a constant integer expression.
    >
    > I do something like
    > #define VERBATIM(...) __VA_ARGS__ //not quite verbatim but OK
    > #define COUNT(...) \
    > VERBATIM(sizeof(struct {char VERBATIM(__VA_ARGS__);}))
    > #define COUNT1(...) \
    > offsetof(VERBATIM(struct {char VERBATIM(__VA_ARGS__), endmark;}), endmark)
    >
    > [Of course, VERBATIM is used to package multi-token argument as one
    > macro parameter.]
    >
    > The evaluation compiles fine:
    > const int x = COUNT(a, b, c);
    >
    > However the conditional fails:
    > #if COUNT(a, b, c) != 3
    > ...

    <snip>
    > And even more errors with
    > #if COUNT1(a, b, c) != 3
    > ...
    >
    > IOW, neither COUNT nor COUNT1 yield a constant integer expression
    > wanted by #if. Compiler diagnostic is less than helpful.
    > What am I doing wrong?


    C is defined in terms of a number of translation phases (eight in all).
    Most deal with lexical matters (continuation lines, comments, finding
    tokens, and so on). Preprocessing happens in phase 4 -- long before the
    main work of translating the code that happens in phase 7.

    Because of this, there is a special definition for constant expressions
    used in #if directives. The main difference is that all identifiers
    that are left over after macro expansion are replaced with 0. This
    applies even to identifiers that would otherwise be keywords. struct,
    char and sizeof are all simply replaced by 0 when your macros are used
    after #if.

    > Another question:
    > Is there a trick to make COUNT() and/or COUNT1() yield 0?


    Sorry, but I can't answer this. There probably is a way -- there is an
    honourable tradition of amazing macro trickery -- but, from a purely
    practical point of view, it is often better to use some other
    preprocessor. This can limit portability, but it's often the way the go
    to get the job done.

    --
    Ben.
    Ben Bacarisse, Nov 20, 2011
    #3
  4. Ark

    Stefan Ram Guest

    Ark <> writes:
    >#if COUNT(a, b, c) != 3


    #define COUNT(...) SELECT_POSITION_4_OF(__VA_ARGS__,LIST43210())
    #define SELECT_POSITION_4_OF(...) SELECT_POSITION_4(__VA_ARGS__)
    #define SELECT_POSITION_4(dummy0,dummy1,dummy2,dummy3,x,...) x
    #define LIST43210() 4,3,2,1,0

    #if COUNT(A)!=1
    #error
    #endif

    #if COUNT(A,B)!=2
    #error
    #endif

    #if COUNT(A,B,C)!=3
    #error
    #endif
    Stefan Ram, Nov 20, 2011
    #4
  5. Ark

    Ark Guest

    On 11/19/2011 8:50 PM, Stefan Ram wrote:
    > Ark<> writes:
    >> #if COUNT(a, b, c) != 3

    >
    > #define COUNT(...) SELECT_POSITION_4_OF(__VA_ARGS__,LIST43210())
    > #define SELECT_POSITION_4_OF(...) SELECT_POSITION_4(__VA_ARGS__)
    > #define SELECT_POSITION_4(dummy0,dummy1,dummy2,dummy3,x,...) x
    > #define LIST43210() 4,3,2,1,0
    >
    > #if COUNT(A)!=1
    > #error
    > #endif
    >
    > #if COUNT(A,B)!=2
    > #error
    > #endif
    >
    > #if COUNT(A,B,C)!=3
    > #error
    > #endif
    >

    That's truly excellent! Thank you very much!
    (Unfortunately, COUNT() is still a 1, not 0.)
    --
    Ark
    Ark, Nov 20, 2011
    #5
  6. Ark

    Ark Guest

    On 11/19/2011 8:37 PM, Ben Bacarisse wrote:
    > Ark<> writes:
    > <snip>
    >> I want a macro to count the number of tokens in a comma-separated
    >> list. I want it to yield a constant integer expression.
    >>
    >> I do something like
    >> #define VERBATIM(...) __VA_ARGS__ //not quite verbatim but OK
    >> #define COUNT(...) \
    >> VERBATIM(sizeof(struct {char VERBATIM(__VA_ARGS__);}))
    >> #define COUNT1(...) \
    >> offsetof(VERBATIM(struct {char VERBATIM(__VA_ARGS__), endmark;}), endmark)
    >>
    >> [Of course, VERBATIM is used to package multi-token argument as one
    >> macro parameter.]
    >>
    >> The evaluation compiles fine:
    >> const int x = COUNT(a, b, c);
    >>
    >> However the conditional fails:
    >> #if COUNT(a, b, c) != 3
    >> ...

    > <snip>
    >> And even more errors with
    >> #if COUNT1(a, b, c) != 3
    >> ...
    >>
    >> IOW, neither COUNT nor COUNT1 yield a constant integer expression
    >> wanted by #if. Compiler diagnostic is less than helpful.
    >> What am I doing wrong?

    >
    > C is defined in terms of a number of translation phases (eight in all).
    > Most deal with lexical matters (continuation lines, comments, finding
    > tokens, and so on). Preprocessing happens in phase 4 -- long before the
    > main work of translating the code that happens in phase 7.
    >
    > Because of this, there is a special definition for constant expressions
    > used in #if directives. The main difference is that all identifiers
    > that are left over after macro expansion are replaced with 0. This
    > applies even to identifiers that would otherwise be keywords. struct,
    > char and sizeof are all simply replaced by 0 when your macros are used
    > after #if.


    Sure. My bad; I should have known better.

    >
    >> Another question:
    >> Is there a trick to make COUNT() and/or COUNT1() yield 0?

    >
    > Sorry, but I can't answer this. There probably is a way -- there is an
    > honourable tradition of amazing macro trickery -- but, from a purely
    > practical point of view, it is often better to use some other
    > preprocessor. This can limit portability, but it's often the way the go
    > to get the job done.
    >


    I know :( I even wrote my own preprocessor (Unimal) but the team I am on
    is willing to use it only when no C native alternative is available.

    --
    Ark
    Ark, Nov 20, 2011
    #6
  7. Ark

    Ark Guest

    On 11/19/2011 8:13 PM, Kaz Kylheku wrote:
    > On 2011-11-19, Ark<> wrote:
    >> However the conditional fails:
    >> #if COUNT(a, b, c) != 3

    >
    > The preprocessing stages in C (a.k.a. "the preprocessor") do not know
    > anything about types.
    >
    > Stuff like:
    >
    > #if sizeof (struct foo) != 3
    >
    > is impossible. Preprocessor expressions are just integer math, e.g:
    >
    > #if PROGRAM_VERSION> 3
    >
    > If PROGRAM_VERSION is not defined, it is replaced with 0.

    Thanks, got it.
    Ark, Nov 20, 2011
    #7
  8. On 11/19/2011 05:44 PM, Ark wrote:
    > I want a macro to count the number of tokens in a comma-separated list.
    > I want it to yield a constant integer expression.


    Almost six years ago, Laurent Deniau posted PP_NARG to comp.std.c; see
    <https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s>.

    More recently, Jens Gustedt posted an enhancement that will correctly
    count the zero-arguments case; see
    <http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/> &
    <http://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/>.

    --Joel
    Joel C. Salomon, Nov 20, 2011
    #8
  9. Ark

    Phil Carmody Guest

    "Joel C. Salomon" <> writes:

    > On 11/19/2011 05:44 PM, Ark wrote:
    > > I want a macro to count the number of tokens in a comma-separated list.
    > > I want it to yield a constant integer expression.

    >
    > Almost six years ago, Laurent Deniau posted PP_NARG to comp.std.c; see
    > <https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s>.
    >
    > More recently, Jens Gustedt posted an enhancement that will correctly
    > count the zero-arguments case; see
    > <http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/> &


    All very clever, but I'm not sure I see why 9 lines of NOISE is better
    than just

    static inline int one_or_two_lazy(int a) { return one_or_two(a, 5); }

    Or, horror of horrors, simply provividing the default parameter. Missing
    it out is purely syntactic sugar, nothing more.

    Phil
    --
    Unix is simple. It just takes a genius to understand its simplicity
    -- Dennis Ritchie (1941-2011), Unix Co-Creator
    Phil Carmody, Nov 21, 2011
    #9
  10. Ark

    Ark Guest

    On 11/20/2011 3:54 PM, Joel C. Salomon wrote:
    > On 11/19/2011 05:44 PM, Ark wrote:
    >> I want a macro to count the number of tokens in a comma-separated list.
    >> I want it to yield a constant integer expression.

    >
    > Almost six years ago, Laurent Deniau posted PP_NARG to comp.std.c; see
    > <https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s>.
    >
    > More recently, Jens Gustedt posted an enhancement that will correctly
    > count the zero-arguments case; see
    > <http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/> &
    > <http://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/>.
    >
    > --Joel

    Thanks, Joel, very interesting.
    But seems too academic all the same.
    From the cost/benefit analysis, it's hard to justify the maintenance
    overhead (+bugs, whether in macros or in compilers) of having COUNT()
    expand to 0.
    If I wanted it VERY badly, I'd go with external preprocessor. For now,
    I'll live with COUNT() expand to 1. It's a simplified version, also
    proposed by Stefan.
    -- Ark
    Ark, Nov 21, 2011
    #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. Davidd Sargent

    Help with counting lines?

    Davidd Sargent, Aug 13, 2004, in forum: Perl
    Replies:
    3
    Views:
    436
    Gunnar Hjalmarsson
    Aug 13, 2004
  2. Engineer
    Replies:
    6
    Views:
    602
    Jeremy Bowers
    May 1, 2005
  3. Replies:
    0
    Views:
    416
  4. =?iso-8859-1?q?Nicolas_Herv=E9?=

    gcc + gprof : basic bloc counting

    =?iso-8859-1?q?Nicolas_Herv=E9?=, Jul 25, 2007, in forum: C Programming
    Replies:
    2
    Views:
    331
    Richard
    Jul 26, 2007
  5. edwardfredriks

    counting up instead of counting down

    edwardfredriks, Sep 6, 2005, in forum: Javascript
    Replies:
    6
    Views:
    185
    Dr John Stockton
    Sep 7, 2005
Loading...

Share This Page