5

is it possible to reset the __COUNTER__ macro at the start of a header file to make its evaluation within the header file consistent over several compile units?

rodrigo
  • 94,151
  • 12
  • 143
  • 190
user5024425
  • 397
  • 3
  • 14
  • 1
    What is the `__COUNTER__` macro? Is it a compiler extension? For which compiler? Can you provide a link to the documentation for it? – Some programmer dude Apr 29 '16 at 08:00
  • 2
    I presume you are using gcc. If you look at the [documentation](https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html) `__COUNTER__` is a helper to enable unique identifiers, therefore even if it were possible you should not reset it. – Euan Smith Apr 29 '16 at 08:05

4 Answers4

10

How about an enum?

enum { COUNTER_BASE = __COUNTER__ };

#define LOCAL_COUNTER (__COUNTER__ - COUNTER_BASE)
Michael
  • 2,118
  • 1
  • 19
  • 25
6

You can set BASE to __COUNTER__ at the top of your header file, and then use __COUNTER__ - BASE later on.

However, do this after you've included all necessary headers, because else thee result would depend on the use of __COUNTER__ within the header guards of those nested include files.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • If you would need a zero based counter BASE should be set to __COUNTER__ + 1 – rouzier Jul 06 '17 at 14:31
  • Because of preprocessor expansion, does `__COUNTER__ - BASE` count as one reference to `__COUNTER__` or two references? – jxh Jul 18 '18 at 18:34
  • I don't think this works... each reference of BASE is replaced by __COUNTER__ and thus depending on order of evaluation, the result will always be 1 or -1. – Michael Oct 11 '18 at 23:35
4

No, there is no way to reset that value.

Take a look at the GCC source that increments the counter:

case BT_COUNTER:
    if (CPP_OPTION (pfile, directives_only) && pfile->state.in_directive)
    cpp_error (pfile, CPP_DL_ERROR,
        "__COUNTER__ expanded inside directive with -fdirectives-only");
    number = pfile->counter++;
    break;

And if you look arount this library, nowhere is the counter modified again. It is default initialized to 0 and then incremented at every use.

Note that the pfile, where the counter variable resides, represents the the preprocessor input, that in this case is the current compilation unit, not the actual file.

SJL
  • 403
  • 2
  • 10
rodrigo
  • 94,151
  • 12
  • 143
  • 190
0

thanks to @Michael, and by using enum you can have complete usage of __COUNTER__ as below:

"source: ESF compiler extension"

//! >>>>>>>>>>>>>>>> Counter >>>>>>>>>>>>>>>>
#pragma region Counter

/* Counter
 * Ex:
 * <code>
CountOn(InitSteps);
int foo(void)
{
    CountIt();
    ...
    CountIt();
    ...
    CountIt();
    ...
}
Counted(InitSteps);
 * </code>
 * */
#define CountOn(name)               enum { name ## _BASE = __COUNTER__ }; const U8 name
#define CountIt(name)               (U8)(__COUNTER__ - (name ## _BASE))
#define Counted(name)               const U8 name = (U8)(__COUNTER__ - (name ## _BASE) -1);

/* alias of Counter
 * Ex:
 * <code>
TakeSteps(InitSteps);
int foo(void)
{
    AddStep();
    ...
    AddStep();
    ...
    AddStep();
    ...
}
TotalSteps(InitSteps);
 * </code>
 * */
#define TakeSteps(name)             CountOn(name)
/* this is invalid to read, want to get value ? use 'CountIt(name)' OR 'NextStep(name)' */
#define AddStep()                   do { __COUNTER__; } while (0);
#define TotalSteps(name)            Counted(name)
/* better use of Counter (on format print 'step, total')
 * 'step' starts at 1
 * Ex:
 * <code>
TakeSteps(InitSteps);
int foo(void)
{
    printf(StepsPRT " Initializing system clock...", NextStep(InitSteps));
    ...
    printf(StepsPRT " Loading configurations...", NextStep(InitSteps));
    ...
    printf(StepsPRT " Applying...", NextStep(InitSteps));
    ...
}
TotalSteps(InitSteps);
 * </code>
 * */
#define NextStep(name)              CountIt(name), name
#define StepsPRT                    "%d of %d"
#define NextStepP                   StepsPRT

#pragma endregion Counter
//! <<<<<<<<<<<<<<<< .Counter <<<<<<<<<<<<<<<<