incr MACRO

Discussion in 'C Programming' started by William Pursell, Feb 26, 2008.

  1. I would like to initialize an array of structs,
    one of whose members is an integer. Some of the
    elements will get an explicit initializer for the
    int, some will take the 0. The value is a monotonically
    increasing counter, starting at 1. For example:

    struct foo t[] = {
    { "apple", 1 },
    { "banana" },
    { "cherry", 2 },
    { "drape", 3 },
    { NULL }
    };


    I don't want to hard code the integer values, and
    would rather do something like:

    struct foo t[] = {
    { "apple", VALUE },
    INCR( VALUE )
    { "banana" },
    { "cherry", VALUE },
    INCR( VALUE )
    { "drape", VALUE },
    { NULL }
    };


    I can't see how to make the preprocessor do this
    for me. Any ideas on how to accomplish this would
    be greatly appreciated.

    (For the curious, the structure I'm initializing
    is a struct argp_option, and I'm trying to initialize
    the group element to get things like --do-this
    --no-do-this to be grouped together . Each time I add
    an option to the option list, Everything below it
    needs to have the value changed. This is easy enough,
    but seems unecessary.)

    --
    William Pursell
     
    William Pursell, Feb 26, 2008
    #1
    1. Advertising

  2. William Pursell

    Eric Sosman Guest

    William Pursell wrote:
    > I would like to initialize an array of structs,
    > one of whose members is an integer. Some of the
    > elements will get an explicit initializer for the
    > int, some will take the 0. The value is a monotonically
    > increasing counter, starting at 1. For example:
    >
    > struct foo t[] = {
    > { "apple", 1 },
    > { "banana" },
    > { "cherry", 2 },
    > { "drape", 3 },
    > { NULL }
    > };
    >
    >
    > I don't want to hard code the integer values, and
    > would rather do something like:
    >
    > struct foo t[] = {
    > { "apple", VALUE },
    > INCR( VALUE )
    > { "banana" },
    > { "cherry", VALUE },
    > INCR( VALUE )
    > { "drape", VALUE },
    > { NULL }
    > };
    >
    >
    > I can't see how to make the preprocessor do this
    > for me. Any ideas on how to accomplish this would
    > be greatly appreciated.


    Must the numbers be consecutive from 1, or is it
    enough that they just increase? Horrible hack:

    struct foo t[] = {
    { "apple", __LINE__ },
    { "banana" },
    { "cherry", __LINE__ ),
    { "damson", __LINE__ },
    { NULL }
    };

    > (For the curious, the structure I'm initializing
    > is a struct argp_option, and I'm trying to initialize
    > the group element to get things like --do-this
    > --no-do-this to be grouped together . Each time I add
    > an option to the option list, Everything below it
    > needs to have the value changed. This is easy enough,
    > but seems unecessary.)


    Maybe you could use an enum to provide the auto-
    incrementing constants?

    enum { APPLE=1, CHERRY, DAMSON };
    struct foo t[] = {
    { "apple", APPLE },
    { "banana" },
    { "cherry", CHERRY ),
    { "damson", DAMSON },
    { NULL }
    };

    Insertions would then be fairly simple:

    enum { APPLE=1, AVOCADO, CHERRY, DAMSON };
    struct foo t[] = {
    { "apple", APPLE },
    { "avocado", AVOCADO },
    { "banana" },
    { "cherry", CHERRY ),
    { "damson", DAMSON },
    { NULL }
    };

    If you need something still more elaborate, it may
    be time to invent a "helper program" that spits out the
    C source, perhaps under control of a "little language."

    --
     
    Eric Sosman, Feb 26, 2008
    #2
    1. Advertising

  3. William Pursell

    Micah Cowan Guest

    William Pursell wrote:
    > I would like to initialize an array of structs,
    > one of whose members is an integer. Some of the
    > elements will get an explicit initializer for the
    > int, some will take the 0. The value is a monotonically
    > increasing counter, starting at 1.


    <snip>

    > I can't see how to make the preprocessor do this
    > for me. Any ideas on how to accomplish this would
    > be greatly appreciated.


    You're right: you can't.

    One solution might be to use dummy values (say, all 0):

    struct foo t[] = {
    { "apple" },
    { "banana" },
    { "cherry" },
    { "drape" },
    { NULL }
    };

    And then, in some initialization code, initialize the keys iteratively:

    struct foo *tp;
    int i;

    for (tp=&t[0], i=0; tp->name != NULL; ++tp, ++i) {
    tp->key = i;
    }

    Assuming the first two members of the struct are named name and key,
    respectively (following the glibc definition for struct argp_option).

    Another way might be to write a small program to generate the structure,
    so that its output can then be compiled, avoiding a small time
    expenditure at startup.

    > (For the curious, the structure I'm initializing
    > is a struct argp_option


    (A GNU-ism, for those not familiar with it.) I haven't used them myself,
    as yet.

    --
    Micah J. Cowan
    Programmer, musician, typesetting enthusiast, gamer...
    http://micah.cowan.name/
     
    Micah Cowan, Feb 26, 2008
    #3
  4. William Pursell

    Kaz Kylheku Guest

    On Feb 26, 12:39 pm, William Pursell <> wrote:
    > I would like to initialize an array of structs,
    > one of whose members is an integer.  Some of the
    > elements will get an explicit initializer for the
    > int, some will take the 0.  The value is a monotonically
    > increasing counter, starting at 1.  For example:
    >
    > struct foo t[] = {
    >         { "apple", 1 },
    >         { "banana" },
    >         { "cherry", 2 },
    >         { "drape", 3 },
    >         { NULL }
    >
    > };
    >
    > I don't want to hard code the integer values, and
    > would rather do something like:
    >
    > struct foo t[] = {
    >         { "apple", VALUE },
    >         INCR( VALUE )
    >         { "banana" },
    >         { "cherry", VALUE },
    >         INCR( VALUE )
    >         { "drape", VALUE },
    >         { NULL }
    >
    > };



    /* file data.h */
    DATA(apple)
    DATA(banana)
    DATA(cherry)
    DATA(grape)



    /* file enum.h */
    #define DATA(X) X,

    /* generate enumeration from data */
    enum {
    #include "data.h"
    }

    #undef DATA


    /* file struct.h */
    #include "enum.h"

    #define DATA(X) { #X, X },

    /* generate table associating strings with enumeration values */
    struct foo t[] = {
    #include "data.h"
    }

    #undef DATA

    Good thing that an extra comma is allowed after an enumertor list and
    initializer list! :)
     
    Kaz Kylheku, Feb 26, 2008
    #4
  5. William Pursell

    Paul Hsieh Guest

    On Feb 26, 2:29 pm, Kaz Kylheku <> wrote:
    > On Feb 26, 12:39 pm, William Pursell <> wrote:
    > > I would like to initialize an array of structs,
    > > one of whose members is an integer. Some of the
    > > elements will get an explicit initializer for the
    > > int, some will take the 0. The value is a monotonically
    > > increasing counter, starting at 1. For example:

    >
    > > struct foo t[] = {
    > > { "apple", 1 },
    > > { "banana" },
    > > { "cherry", 2 },
    > > { "drape", 3 },
    > > { NULL }

    >
    > > };

    >
    > > I don't want to hard code the integer values, and
    > > would rather do something like:

    >
    > > struct foo t[] = {
    > > { "apple", VALUE },
    > > INCR( VALUE )
    > > { "banana" },
    > > { "cherry", VALUE },
    > > INCR( VALUE )
    > > { "drape", VALUE },
    > > { NULL }

    >
    > > };

    >
    > /* file data.h */
    > DATA(apple)
    > DATA(banana)
    > DATA(cherry)
    > DATA(grape)
    >
    > /* file enum.h */
    > #define DATA(X) X,
    >
    > /* generate enumeration from data */
    > enum {
    > #include "data.h"
    > }
    >
    > #undef DATA
    >
    > /* file struct.h */
    > #include "enum.h"
    >
    > #define DATA(X) { #X, X },
    >
    > /* generate table associating strings with enumeration values */
    > struct foo t[] = {
    > #include "data.h"
    > }
    >
    > #undef DATA
    >
    > Good thing that an extra comma is allowed after an enumerator list and
    > initializer list! :)


    Excellent idea, but this has the problem of invading name space.
    I.e., you need to defined the symbols apple, banana, cherry and so
    on. You also seem to have missed the fact that the OP wants to skip
    an increment between banana and cherry. To get around this:

    /* file data.h */
    #ifndef REPT
    #define REPT(x,y) DATA(x)
    #endif
    #define glue_aux(x,y) x ## y
    #define glue(x,y) glue_aux(x,y)
    DATA(apple)
    DATA(banana)
    REPT(cherry, banana)
    DATA(grape)
    #undef glue
    #undef glue_aux

    Then:

    /* file enum.h */
    #define DATA(X) glue(COUNTER_,X),
    #define REPT(X,Y) glue(COUNTER_,X) = glue(COUNTER_,Y),
    enum counter {
    #include "data.h"
    };
    #undef DATA

    /* file struct.h */
    #include "enum.h"
    #define DATA(X) { #X, glue(COUNTER_,X) },
    struct foo {
    char * string;
    enum counter idx;
    } t[] = {
    #include "data.h"
    };
    #undef DATA

    Keeping your name space clean while giving you the strings and indexes
    as expected.

    --
    Paul Hsieh
    http://www.pobox.com/~qed/
    http://bstring.sf.net/
     
    Paul Hsieh, Feb 26, 2008
    #5
  6. William Pursell

    Kaz Kylheku Guest

    On Feb 26, 2:29 pm, Kaz Kylheku <> wrote:
    > On Feb 26, 12:39 pm, William Pursell <> wrote:
    >
    >
    >
    >
    >
    > > I would like to initialize an array of structs,
    > > one of whose members is an integer.  Some of the
    > > elements will get an explicit initializer for the
    > > int, some will take the 0.  The value is a monotonically
    > > increasing counter, starting at 1.  For example:

    >
    > > struct foo t[] = {
    > >         { "apple", 1 },
    > >         { "banana" },
    > >         { "cherry", 2 },
    > >         { "drape", 3 },
    > >         { NULL }

    >
    > > };

    >
    > > I don't want to hard code the integer values, and
    > > would rather do something like:

    >
    > > struct foo t[] = {
    > >         { "apple", VALUE },
    > >         INCR( VALUE )
    > >         { "banana" },
    > >         { "cherry", VALUE },
    > >         INCR( VALUE )
    > >         { "drape", VALUE },
    > >         { NULL }

    >
    > > };

    >
    >   /* file data.h */
    >   DATA(apple)
    >   DATA(banana)
    >   DATA(cherry)
    >   DATA(grape)


    Oops, I missed the requirement about some entries being zero. If the
    incrementing counter is allowed to skip, then you can of course do
    this:

    DATA(apple,1)
    DATA(banana,0)
    DATA(cherry,1)
    DATA(grape,1)

    >   /* file enum.h */
    >   #define DATA(X) X,


    #define DATA(X, Y) X,

    >   /* generate enumeration from data */
    >   enum {
    >   #include "data.h"
    >   }
    >
    >   #undef DATA
    >
    >   /* file struct.h */
    >   #include "enum.h"
    >
    >   #define DATA(X) { #X, X },


    #define DATA(X, Y) { #X, (Y) * (X)},

    Now, how about that requirement to skip values, so that banana is
    zero, and then cherry continues where apple left off.

    /* data.h */
    DATA(apple,)
    DATA(banana,= 0)
    DATA(cherry,= apple + 1)
    DATA(grape,)

    It's not exactly automatic, since you have to program the skips with
    these backreferences among the data.

    In the enum.h, we define the DATA macro like this:

    #define DATA(X, Y) X Y,

    In struct.h, we define DATA just like in the original version:

    #define DATA(X) { #X, X },
     
    Kaz Kylheku, Feb 26, 2008
    #6
  7. William Pursell

    Kaz Kylheku Guest

    On Feb 26, 2:57 pm, Paul Hsieh <> wrote:
    > Excellent idea, but this has the problem of invading name space.
    > I.e., you need to defined the symbols apple, banana, cherry and so
    > on.  You also seem to have missed the fact that the OP wants to skip
    > an increment between banana and cherry.  To get around this:
    >
    >    /* file data.h */
    >    #ifndef REPT
    >    #define REPT(x,y) DATA(x)
    >    #endif
    >    #define glue_aux(x,y) x ## y
    >    #define glue(x,y) glue_aux(x,y)
    >    DATA(apple)
    >    DATA(banana)
    >    REPT(cherry, banana)
    >    DATA(grape)


    Yes, but unfortunately the value for banana also has to vanish to
    zero. So you might want an additional data form ZERO:

    ZERO(banana)
    REPT(cherry, apple + 1)

    The default reduction of ZERO is to just pull out the name, like with
    REPT:

    #ifndef ZERO
    #define ZERO(x, y) DATA(x)
    #endif


    >    #undef glue
    >    #undef glue_aux
    >
    > Then:
    >
    >    /* file enum.h */
    >    #define DATA(X) glue(COUNTER_,X),
    >    #define REPT(X,Y) glue(COUNTER_,X) = glue(COUNTER_,Y),


    And then for enums, ZERO of course does this:

    #define ZERO(X, Y) glue(COUNTER_,X) = 0,

    Very good. I like this idea of variants that can be mapped to a
    uniform representation with a default implementation, or to separate
    forms where needed.
     
    Kaz Kylheku, Feb 26, 2008
    #7
  8. On Feb 26, 9:23 pm, Eric Sosman <> wrote:
    > William Pursell wrote:
    > > I would like to initialize an array of structs,
    > > one of whose members is an integer. Some of the
    > > elements will get an explicit initializer for the
    > > int, some will take the 0. The value is a monotonically
    > > increasing counter, starting at 1. For example:


    >
    > Must the numbers be consecutive from 1, or is it
    > enough that they just increase? Horrible hack:

    <snip example using __LINE__>

    It is enough that they increase. Using __LINE__
    is absolutely brilliant, and not a "Horrible hack"
    at all.

    > Maybe you could use an enum to provide the auto-
    > incrementing constants?


    Also acceptable.

    > If you need something still more elaborate, it may
    > be time to invent a "helper program" that spits out the
    > C source, perhaps under control of a "little language."


    This was considered, but rejected on the grounds that
    I only insert an option rarely, and am only up to
    7 values, so hand editing has been relatively painless
    and it wasn't worth the effort. Thanks for the __LINE__
    suggestion...I'll run with it.

    Also thanks to Kaz and Paul, who also provided some
    really good ideas.

    --
    William Pursell
     
    William Pursell, Feb 27, 2008
    #8
  9. On Feb 26, 9:42 pm, Micah Cowan <> wrote:
    > William Pursell wrote:
    > > (For the curious, the structure I'm initializing
    > > is a struct argp_option

    >
    > (A GNU-ism, for those not familiar with it.) I haven't used them myself,
    > as yet.


    I highly recommend it. I just implemented my first child parser,
    and am using it to give me some standard option parsing
    including and a -h option that pipes the help message through
    $PAGER, all with one line of code! (I can't believe I never
    thought of doing that before.) It's really, really nice,
    although (at first appearance) a bit kludgy to use.
     
    William Pursell, Feb 27, 2008
    #9
  10. William Pursell

    Eric Sosman Guest

    William Pursell wrote:
    > On Feb 26, 9:23 pm, Eric Sosman <> wrote:
    >> William Pursell wrote:
    >>> I would like to initialize an array of structs,
    >>> one of whose members is an integer. Some of the
    >>> elements will get an explicit initializer for the
    >>> int, some will take the 0. The value is a monotonically
    >>> increasing counter, starting at 1. For example:

    >
    >> Must the numbers be consecutive from 1, or is it
    >> enough that they just increase? Horrible hack:

    > <snip example using __LINE__>
    >
    > It is enough that they increase. Using __LINE__
    > is absolutely brilliant, and not a "Horrible hack"
    > at all.


    I'm not sure I merit the brilliancy accolade, but
    I *am* sure about calling my suggestion a "horrible hack."
    For reference, here it is again:

    struct foo t[] = {
    { "apple", __LINE__ },
    { "banana" },
    { "cherry", __LINE__ ),
    { "damson", __LINE__ },
    { NULL }
    };

    I call it horrible because it's fragile. The typical
    C textbook will describe "white space" in source, and will
    tell you that all forms of white space are equivalent: spaces,
    tabs, comments, newlines, they're all the same. So, let's
    take advantage of this equivalence to format the source
    more compactly:

    struct foo t[] = { { "apple", __LINE__ }, { "banana" },
    { "cherry", __LINE__ ), { "damson", __LINE__ },
    { NULL } };

    Oops!

    --
    Eric Sosman
    lid
     
    Eric Sosman, Feb 27, 2008
    #10
  11. Eric Sosman <> writes:
    > William Pursell wrote:
    >> On Feb 26, 9:23 pm, Eric Sosman <> wrote:
    >>> William Pursell wrote:
    >>>> I would like to initialize an array of structs,
    >>>> one of whose members is an integer. Some of the
    >>>> elements will get an explicit initializer for the
    >>>> int, some will take the 0. The value is a monotonically
    >>>> increasing counter, starting at 1. For example:

    >>
    >>> Must the numbers be consecutive from 1, or is it
    >>> enough that they just increase? Horrible hack:

    >> <snip example using __LINE__>
    >>
    >> It is enough that they increase. Using __LINE__
    >> is absolutely brilliant, and not a "Horrible hack"
    >> at all.

    >
    > I'm not sure I merit the brilliancy accolade, but
    > I *am* sure about calling my suggestion a "horrible hack."
    > For reference, here it is again:
    >
    > struct foo t[] = {
    > { "apple", __LINE__ },
    > { "banana" },
    > { "cherry", __LINE__ ),
    > { "damson", __LINE__ },
    > { NULL }
    > };
    >
    > I call it horrible because it's fragile. The typical
    > C textbook will describe "white space" in source, and will
    > tell you that all forms of white space are equivalent: spaces,
    > tabs, comments, newlines, they're all the same. So, let's
    > take advantage of this equivalence to format the source
    > more compactly:
    >
    > struct foo t[] = { { "apple", __LINE__ }, { "banana" },
    > { "cherry", __LINE__ ), { "damson", __LINE__ },
    > { NULL } };
    >
    > Oops!


    I thought it fell only slightly short of brilliance; I find it clever,
    though perhaps a little excessively so. (A comment reminding
    maintainers not to put two occurrences on the same line would probably
    suffice to avoid the problem you describe. Or a check routine, not
    called in production mode, could confirm that all the values are
    unique.

    But when I saw it, I thought of an another potential problem. As the
    code is maintained, and lines are added or removed before the
    declaration, the values are going to change. If the code is well
    written to depend only on the uniqueness of each value, that's not
    going to be a problem. But if there's a subtle dependency on the
    specific values, it could cause trouble. For example, imagine that
    there's an implicit assumption that each value is no more than a
    2-digit number. The code could break years later, when an inserted
    declaration pushes the last usage of __LINE__ to line 100. That's
    probably an unlikely scenario, but it could be fragile in other ways
    I haven't thought of.

    Then again, ordinary enumerated types have the same problem, so
    perhaps I'm being too paranoid (though that's often better than not
    being paranoid enough).

    --
    Keith Thompson (The_Other_Keith) <>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Feb 27, 2008
    #11
  12. On Tue, 26 Feb 2008 12:39:11 -0800, William Pursell wrote:

    > I would like to initialize an array of structs,
    > one of whose members is an integer. Some of the
    > elements will get an explicit initializer for the
    > int, some will take the 0. The value is a monotonically
    > increasing counter, starting at 1. For example:

    [...]

    This is not a solution to your problem. I would go with Eric Sosmans
    "neat hack" and take Keith Thompson's comment to heart:

    http://groups.google.com/group/comp.lang.c/msg/cadb1cc2eef560ee


    Anyway, FWIW, here is a simple way to do math solely in the pre-processor:
    ________________________________________________________________________
    #include <stdio.h>


    #define PLACE_X(t)t
    #define PLACE(t)PLACE_X(t)


    #define CONCAT_X(t0, t1)t0##t1
    #define CONCAT(t0, t1)CONCAT_X(t0, t1)


    #define SELECT_0(t0, t1)t0
    #define SELECT_1(t0, t1)t1
    #define SELECT(t, ts)CONCAT(SELECT_, t)ts


    #define MATHTBL_1()(2, 0)
    #define MATHTBL_2()(3, 1)
    #define MATHTBL_3()(4, 2)
    #define MATHINC(t)SELECT(0, CONCAT(MATHTBL_, t)())
    #define MATHDEC(t)SELECT(1, CONCAT(MATHTBL_, t)())


    int main(void) {
    printf("1 + 1 = %d\n", MATHINC(1));
    printf("2 + 1 = %d\n", MATHINC(2));
    printf("3 + 1 = %d\n", MATHINC(3));
    printf("1 - 1 = %d\n", MATHDEC(1));
    printf("2 - 1 = %d\n", MATHDEC(2));
    printf("3 - 1 = %d\n", MATHDEC(3));


    /*-----------------------------------------------------------*/
    puts("\n\n\n______________________________________________\n\
    press <ENTER> to exit...");
    getchar();
    return 0;
    }

    ________________________________________________________________________



    The 'MATHTBL_X' and 'SELECT_X' macros can also be extended to
    multiplication and division.
     
    Chris Thomasson, Feb 27, 2008
    #12
    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. again some incr/decrement question

    , Jul 2, 2005, in forum: C Programming
    Replies:
    1
    Views:
    302
    Denis Kasak
    Jul 2, 2005
  2. Morton Goldberg

    Using [incr Widgets] in Ruby/Tk on OS X

    Morton Goldberg, Sep 1, 2006, in forum: Ruby
    Replies:
    5
    Views:
    230
    Hidetoshi NAGAI
    Sep 1, 2006
  3. Morton Goldberg
    Replies:
    0
    Views:
    124
    Morton Goldberg
    Sep 6, 2006
  4. Morton Goldberg

    [Ruby/Tk example] Calendar [incr Widget]

    Morton Goldberg, Sep 5, 2006, in forum: Ruby
    Replies:
    0
    Views:
    232
    Morton Goldberg
    Sep 5, 2006
  5. Morton Goldberg

    [Ruby/Tk example] Feedback [incr Widget]

    Morton Goldberg, Sep 5, 2006, in forum: Ruby
    Replies:
    0
    Views:
    152
    Morton Goldberg
    Sep 5, 2006
Loading...

Share This Page