Macro counting invocations

N

Noob

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

Ben Bacarisse

Noob said:
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 */

Or fear of undefined behaviour... 1UL << 31 is OK, but 1 << 31 is
undefined when int can't represent 2^31 (^ meaning exponentiation
here).
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?

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

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.
Portability is not very important here, so I could maybe use an unsigned
long long bitmap (64 bits on my platform)... Bleh...

I would make the bitmaps unsigned, and long has the advantage that you
know that 1UL << 31 is representable.

<snip>
 
E

Eric Sosman

Noob said:
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 */

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;
}
unsigned long bitmap2 = 0;
if (GOO_init() != 0) bitmap2 |= (1 << 0);
etc

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

you could eliminate magic said:
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)

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

Macros seem the wrong tool for the job; an array of function
pointers seems much neater.
 
N

Nobody

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];

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];
...
 
P

Paul N

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

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

Nick

Paul N said:
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.

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.
 

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,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top