CPP Macro: счетчик, который дает количество экземпляров / вызовов - PullRequest
2 голосов
/ 27 октября 2010

Я хочу иметь макрос препроцессора C , который знает количество вызовов / макросов этого макроса.Пример:

int main() {
  printf("%d\n", MACRO());
  printf("%d\n", MACRO());
}

Следует напечатать

0
1

Возможно ли что-то подобное?

Обратите внимание, что не достаточно, чтобы переслать этофункция, предложенная ниже.Он должен работать в следующем контексте:

// global variable
std::vector<bool> calls_hit;

#define OTHER_MACRO() \
{ \
    const int counter = MACRO(); \
    calls_hit.resize(std::max(calls_hit.size(), counter)); \
    calls_hit[counter] = true; \
}

Ответы [ 3 ]

5 голосов
/ 27 октября 2010

Почему это должен быть макрос? В любом случае, вы можете просто обернуть функцию статическим счетчиком в макрос:

int count_calls() {
    static count = 0;
    return count++;
}

#define MACRO() count_calls()
2 голосов
/ 31 декабря 2011

У меня есть решение, которое похоже (в использовании) на &#95;&#95;COUNTER&#95;&#95;, но не ограничено одним счетчиком - вы можете определить много счетчиков, как вам нравится.

В этом используется специфичный для gccособенность, но должна быть в состоянии сделать то же самое в другом наборе инструментов.

static int getpos(int lineno); // forward declaration

#define MY_COUNTER ({                                                    \
            static const int mark __attribute__((LSEG,used)) = __LINE__; \
            getpos(__LINE__);                                            \
})

static int __attribute__((noinline)) getpos(int lineno) {
    static const int mark __attribute__((LSEG,used)) = __LINE__;
    const int *p = &mark;
    int i;
    for (i = 0; *p++ != lineno; i++);
    return i;
}

В вышеприведенном коде LSEG расширяется до чего-то вроде секции (". rodata.line01234"), сгенерированной из &#95;&#95;LINE&#95;&#95; информации.

Вот пояснение того, как это работает:

  1. Каждый раз, когда вы используете макрос MY_COUNTER, он заменяется 2 фрагментами кода: 1) кодом, который помещает значение &#95;&#95;LINE&#95;&#95; в сегмент памяти, заданный макросом LSEGи 2) код, вызывающий функцию getpos (&#95;&#95;LINE&#95;&#95;), которая возвращает количество вызовов, записанных до данной строки.
  2. Макрос LSEG расширяется до спецификатора раздела с номером строки (например: section (". rodata).line01234 ")).
  3. Указав компоновщик для сортировки сегмента в алфавитном порядке (-Wl, - sort-сегмент = имя с GNU ld), вы можете быть уверены, что все добавленные значения &#95;&#95;LINE&#95;&#95; находятся в том порядке, в котором они былиб.
  4. АВо время выполнения функция getpos (&#95;&#95;LINE&#95;&#95;) просматривает сегмент памяти и возвращает количество вызовов, записанных до данной строки.

Надеюсь, это поможет.

1 голос
/ 29 октября 2010

Что не так с

// global variable
std::vector<bool> calls_hit;

inline void a_function_since_this_is_not_C_after_all()
{
  static unsigned int hits = 0;
  const int counter = hits++;
  calls_hit.resize(std::max(calls_hit.size(), counter));
  calls_hit[counter] = true;
}
...