Macro counting invocations

Discussion in 'C Programming' started by Noob, Nov 17, 2009.

  1. Noob

    Noob Guest

    Hello,

    I have a long list of (40-50) initialization functions which I must call
    at the start of an application.

    As of now, the code looks like this:

    unsigned long bitmap = 0;
    if (FOO_init() != 0) bitmap |= (1 << 0);
    if (BAR_init() != 0) bitmap |= (1 << 1);
    if (BAZ_init() != 0) bitmap |= (1 << 2);
    ....
    if (BOB_init() != 0) bitmap |= (1 << 30);
    /* 1 << 31 is not used, out of superstition I imagine */

    unsigned long bitmap2 = 0;
    if (GOO_init() != 0) bitmap2 |= (1 << 0);
    etc

    I am trying to write a macro that would take a function name and spit
    the corresponding invocation and potential bit-setting.

    WUNDER_MACRO(FOO_init);
    WUNDER_MACRO(BAR_init);
    would expand to
    if (FOO_init() != 0) bitmap |= (1 << 0);
    if (BAR_init() != 0) bitmap |= (1 << 1);

    I have two problems.

    1) How do I write a macro that counts how many times it has been invoked?

    So that the i-th invocation can produce bitmap |= (1 << i)

    2) I'm not sure how to handle the fact that I have more than 32
    functions to call.

    Portability is not very important here, so I could maybe use an unsigned
    long long bitmap (64 bits on my platform)... Bleh...

    Or is there no easy way to "clean up" this code, and I should leave it
    as it is?

    Any and all suggestion welcome.

    Regards.
     
    Noob, Nov 17, 2009
    #1
    1. Advertisements

  2. Or fear of undefined behaviour... 1UL << 31 is OK, but 1 << 31 is
    undefined when int can't represent 2^31 (^ meaning exponentiation
    here).
    Using a variable. You need to declare and initialise it, but
    increment it once in the macro expansion. Is there a reason you are
    not using a function for this?
    I'd switch to an array. Can you change bitmap and bitmap2 to
    bitmap[2]? If so bitmap[count/32] |= (1UL << (count % 32)); does
    pretty much what you want.
    I would make the bitmaps unsigned, and long has the advantage that you
    know that 1UL << 31 is representable.

    <snip>
     
    Ben Bacarisse, Nov 17, 2009
    #2
    1. Advertisements

  3. Noob

    Eric Sosman Guest

    Ugh. Why not use an array of function pointers?

    typedef int (*InitFunc)(void);
    static const InitFunc init[] = {
    FOO_init, BAR_init, BAZ_init, ..., };
    #define INITFUNCS (sizeof init / sizeof init[0] )

    unsigned long bitmap = 0;
    for (unsigned int i = 0; i < INITFUNCS; ++i) {
    if (init() != 0)
    bitmap |= 1UL << i;
    }
    Changing to `unsigned long long' (and to `1ULL << i') would
    take you up to at least sixty-four functions. Or you could make
    bitmap be an array of a suitable number of `unsigned long':

    unsigned long bitmap[(INITFUNCS + 31) / 32];
    for (unsigned int i = 0; i < INITFUNCS; ++i) {
    if (init() != 0)
    bitmap[i >> 5] |= 1UL << (i & 0x1F);
    }

    I don't think it can be done. The macro expansion cannot
    produce a preprocessor directive, so (in particular) it cannot
    produce a #define or anything like it. #define is almost the
    only way to give a macro a new value, so ...

    If you could guarantee that the initialization calls would
    all be on consecutive lines, you could do something like

    #define CALLIT(func) \
    if ((func)() != 0) bitmap |= 1ULL << (__LINE__ - base)
    const int base = __LINE__ + 1;
    CALLIT(FOO_init);
    CALLIT(BAR_init);
    ...

    However, no jury in the world would convict the slayer of
    someone who wrote this sort of abomination. In fact, the killer
    would probably get a medal.
    Macros seem the wrong tool for the job; an array of function
    pointers seems much neater.
     
    Eric Sosman, Nov 17, 2009
    #3
  4. Noob

    Nobody Guest

    Given that 64-bit "long"s are pretty common nowadays:

    #define ULONG_BITS (sizeof(unsigned long)*CHAR_BIT)
    ...
    unsigned long bitmap[(INITFUNCS + ULONG_BITS-1) / ULONG_BITS];
    ...
     
    Nobody, Nov 17, 2009
    #4
  5. Noob

    Paul N Guest

    What is bitmap going to be used for? I would have thought that, if
    you're going to set a bit in the bitmap to indicate whether a function
    has initialised properly or not, sooner or later you are going to want
    to associate that value with the function somehow. From a value of 2,
    say, you want to know that BAR went wrong, so it seems odd for your
    code to merely say that BAR's indicator is between FOO's and BAZ's.
     
    Paul N, Nov 17, 2009
    #5
  6. Noob

    Nick Guest

    In which case I'm pretty sure you could do something horrible with a
    doubly included header file, roughly like this (utterly untested) code:

    header file (horrid.h):
    ITEM(foo,FOO)
    ITEM(bar,BAR)
    ITEM(baz,BAZ)
    ....
    ITEM(bob,BOB)

    then, in your main code:
    #define ITEM(a,b) bf_##a,
    enum bitflags {
    #include "horrid.h"
    };
    #undef ITEM

    #define ITEM(a,b) IF (b##_init() != 0) bitmap |= (1 << bf_##a);
    #include "horrid.h"
    #undef ITEM

    I've used both versions there, as you might want to give your functions
    and enums names that differ more than this.

    Not only does this do what you want, it also means you can check any of
    the bit flags with (for example) bitmap[bf_baz], and it also confuses
    the hell out of anyone reading the code. What more do you want.

    Nick, who admits he's used this technique - particularly to associate
    strings and enums.
     
    Nick, Nov 18, 2009
    #6
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.