cpp hacking: bump FOO by 1

Fred Wright fw at fwright.net
Wed Sep 2 23:42:17 UTC 2020


On Sun, 30 Aug 2020, Hal Murray via devel wrote:

> Is there any way to do something like
> #define FOO $FOO+1
>
> I want to keep track of the number of times a macro has been called.  That
> seems like something that would happen often enough that there would be a
> standard recipe but I haven't seen it.  (Or didn't recognize it.)
>
> ----------
>
> The context is the code in ntp_control that is responding to ntpq requests to
> read a variable.  It needs to translate a string (name of variable to read) to
> a subroutine to print that variable.  Current code looks like:
>
> #define CS_REFID                6
>        { CS_REFID,             RO|DEF, "refid" },
> #define CS_REFTIME              7
>        { CS_REFTIME,           RO|DEF, "reftime" },
> #define CS_POLL                 8
>        { CS_POLL,              RO|DEF, "tc" },
> #define CS_PEERID               9
>        { CS_PEERID,            RO|DEF, "peer" },
>
> That sets up the table to search.  The table is big (~100 slots) so it's a
> real pain to insert a new slot.
>
> Later on, there is a giant select that uses those CS_xxx tags:
>
>        case CS_ROOTDELAY:
>                ctl_putdbl(sys_var[CS_ROOTDELAY].text,
>                           sys_vars.sys_rootdelay * MS_PER_S);
>                break;
>
>        case CS_ROOTDISPERSION:
>                ctl_putdbl(sys_var[CS_ROOTDISPERSION].text,
>                           sys_vars.sys_rootdisp * MS_PER_S);
>                break;
>
> ---------

The usual way to do this sort of thing with the lame macro processor known 
as cpp is as follows:

First define a "master macro" whose body is a series of invocations of an 
entry macro, with all the necessary properties being provided as 
arguments.  Then, for each table or other use:

1) Define the entry macro to generate the appropriate content from the 
appropriate arguments.

2) Invoke the master macro.

3) Undefine the entry macro (so it's ready for next time).

I can't make a precise example since you chose different entries for the 
two parts of your example above, but for the first part one could have 
something like this:

#define CS_ENTRIES \
 	CS_ENTRY(REFID, RO|DEF, "refid") \
 	CS_ENTRY(POLL, RO|DEF, "tc") \
 	CS_ENTRY(PEERID, RO|DEF, "peer") \

Then, to define the numeric codes:

#define CS_ENTRY(sym, flags, name) CS_##sym,
enum cs_index {
 	CS_ENTRIES
 	CS_MAXVAL	// Maximum value +1
};
#undef CS_ENTRY

For a table of names:

#define CS_ENTRY(sym, flags, name) name,
static const char * const cs_names[] = {
 	CS_ENTRIES
};
#undef CS_ENTRY

> One approach would be to have an external program do the equivalent of the cpp
> processing that we would like to do.  That would take some waf hacking, but
> shouldn't be a big deal.

An unnecessary complication.

Fred Wright


More information about the devel mailing list