У меня есть решение, которое похоже (в использовании) на __COUNTER__
, но не ограничено одним счетчиком - вы можете определить много счетчиков, как вам нравится.
В этом используется специфичный для 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"), сгенерированной из __LINE__
информации.
Вот пояснение того, как это работает:
- Каждый раз, когда вы используете макрос MY_COUNTER, он заменяется 2 фрагментами кода: 1) кодом, который помещает значение
__LINE__
в сегмент памяти, заданный макросом LSEGи 2) код, вызывающий функцию getpos (__LINE__
), которая возвращает количество вызовов, записанных до данной строки. - Макрос LSEG расширяется до спецификатора раздела с номером строки (например: section (". rodata).line01234 ")).
- Указав компоновщик для сортировки сегмента в алфавитном порядке (-Wl, - sort-сегмент = имя с GNU ld), вы можете быть уверены, что все добавленные значения
__LINE__
находятся в том порядке, в котором они былиб. - АВо время выполнения функция getpos (
__LINE__
) просматривает сегмент памяти и возвращает количество вызовов, записанных до данной строки.
Надеюсь, это поможет.