多个__COUNTER__ C
Multiple __COUNTER__ C
我正在研究预处理器和 c。尝试实现我自己的事件和层次结构系统。
但是我遇到了一个问题。我正在尝试静态定义可以初始化的 "modules",以及一些预先静态定义的事件。对于我使用的事件,COUNTER 效果很好。但我不想混淆模块 ID 和事件 ID。
我想要实现的目标的简化版本:
hierarchy.h
#define HIERARCHY_DEFINE(NAME) int hierarchyId = __COUNTER__
event.h
#define EVENT_REGISTER(NAME) int eventId = __COUNTER__
main.c
#include "event.h"
#include "hierarchy.h"
EVENT_REGISTER(EventOne);
HIERARCHY_DEFINE(ModuleOne);
EVENT_REGISTER(EventTwo);
int main(void){
printf("events(%d, %d) modules(%d)\n",EventOne,EventTwo,ModuleOne);
return 1;
}
这将打印出:
events(0, 2) modules(1)
当我试图达到:
events(0, 1) modules(0)
我环顾四周,有人说我无法自己创建计数器。看到了升压计数器,但这也没有达到我想要的效果。
有人知道我该如何处理这种情况吗?
谢谢!
编辑:
对我的代码的实际外观略作修改
struct Event{
uint8_t eventId;
uint8_t * data;
const char * description;
};
#define EVENT_REGISTER(eventName, desc)\
static Event eventName = {.eventId = __COUNTER__, .data = 0, .description = desc }
EVENT_REGISTER(Timer_5, "Timer 5 hZ");
除非您对标识符有额外的要求,否则可以执行以下操作:
definitions.inc
EVENT_REGISTER(Timer_5, "Timer 5 Hz")
EVENT_REGISTER(Timer_10, "Timer 10 Hz")
MODULE_REGISTER(Module_SSH)
MODULE_REGISTER(Module_NCO)
#undef EVENT_REGISTER
#undef MODULE_REGISTER
app.c
#define EVENT_REGISTER(a, d) a,
#define MODULE_REGISTER(a)
enum events {
#include "definitions.inc"
};
#define EVENT_REGISTER(a, d)
#define MODULE_REGISTER(a) a,
enum modules {
#include "definitions.inc"
};
struct Event {
uint8_t event_id;
uint8_t *data;
const char *description;
};
#define MODULE_REGISTER(a)
#define EVENT_REGISTER(a, d) static struct Event Event_##a = { .event_id = a, \
.data = NULL, \
.description = d \
};
#include "definitions.inc"
int main (int argc, char **argv)
{
printf("events(%d, %d) modules(%d)\n", Timer_10, Timer_5, Module_SSH);
return EXIT_SUCCESS;
}
您必须:
- 在运行时分配 ID,
- 手动分配 ID
- 或者将所有事件和模块定义放在一个地方。
假设您有 a.c
和 b.c
,它们分别包含一些 EventA
和 EventB
定义。由于它们是独立的编译单元,编译器无法为它们分配 non-overlapping id。编译 b.c
,它甚至不知道还有另一个 a.c
已经分配了 id 1
。
对于第一个,有一个像这样的 RegisterEvent
函数:
void RegisterEvent(Event* event){
static int nextEventId = 0;
event->eventId = nextEventId;
}
并为您需要的每个 Event
调用它。
第二个很明显,但是乏味且容易出错。
对于第三种解决方案,您可以使用X macro。
X-list 您的所有活动:
#define EventList \
Event(FirstEvent, "FirstEvent") \
Event(Timer_1, "Timer 1 hZ") \
...
Event(Timer_5, "Timer 5 hZ")
现在,在 header 中您要声明所有事件(例如,events.h
):
#define Event(name, desc) EventID ## name,
enum EventID{
EventIDZero = 0,
EventList
EventIDCount
};
#undef Event
#define Event(name, desc) \
extern Event name;
EventList
#undef Event
并且在您的事件定义所在的单个编译单元中(例如,events.c
):
#include "events.h"
#define Event(name, desc) \
Event name = {.eventId = EventID ## name, .data = 0, .description = desc };
EventList
#undef Event
宏扩展后,events.c
看起来像(为了便于阅读而略作编辑):
enum EventID{
EventIDZero = 0,
EventIDFirstEvent, EventIDTimer_1, EventIDTimer_5,
EventIDCount
};
extern Event FirstEvent;
extern Event Timer_1;
extern Event Timer_5;
Event FirstEvent = {.eventId = EventIDFirstEvent, .data = 0, .description = "FirstEvent" };
Event Timer_1 = {.eventId = EventIDTimer_1, .data = 0, .description = "Timer 1 hZ" };
Event Timer_5 = {.eventId = EventIDTimer_5, .data = 0, .description = "Timer 5 hZ" };
模块也是如此。
我正在研究预处理器和 c。尝试实现我自己的事件和层次结构系统。 但是我遇到了一个问题。我正在尝试静态定义可以初始化的 "modules",以及一些预先静态定义的事件。对于我使用的事件,COUNTER 效果很好。但我不想混淆模块 ID 和事件 ID。
我想要实现的目标的简化版本:
hierarchy.h
#define HIERARCHY_DEFINE(NAME) int hierarchyId = __COUNTER__
event.h
#define EVENT_REGISTER(NAME) int eventId = __COUNTER__
main.c
#include "event.h"
#include "hierarchy.h"
EVENT_REGISTER(EventOne);
HIERARCHY_DEFINE(ModuleOne);
EVENT_REGISTER(EventTwo);
int main(void){
printf("events(%d, %d) modules(%d)\n",EventOne,EventTwo,ModuleOne);
return 1;
}
这将打印出:
events(0, 2) modules(1)
当我试图达到:
events(0, 1) modules(0)
我环顾四周,有人说我无法自己创建计数器。看到了升压计数器,但这也没有达到我想要的效果。
有人知道我该如何处理这种情况吗?
谢谢!
编辑:
对我的代码的实际外观略作修改
struct Event{
uint8_t eventId;
uint8_t * data;
const char * description;
};
#define EVENT_REGISTER(eventName, desc)\
static Event eventName = {.eventId = __COUNTER__, .data = 0, .description = desc }
EVENT_REGISTER(Timer_5, "Timer 5 hZ");
除非您对标识符有额外的要求,否则可以执行以下操作:
definitions.inc
EVENT_REGISTER(Timer_5, "Timer 5 Hz")
EVENT_REGISTER(Timer_10, "Timer 10 Hz")
MODULE_REGISTER(Module_SSH)
MODULE_REGISTER(Module_NCO)
#undef EVENT_REGISTER
#undef MODULE_REGISTER
app.c
#define EVENT_REGISTER(a, d) a,
#define MODULE_REGISTER(a)
enum events {
#include "definitions.inc"
};
#define EVENT_REGISTER(a, d)
#define MODULE_REGISTER(a) a,
enum modules {
#include "definitions.inc"
};
struct Event {
uint8_t event_id;
uint8_t *data;
const char *description;
};
#define MODULE_REGISTER(a)
#define EVENT_REGISTER(a, d) static struct Event Event_##a = { .event_id = a, \
.data = NULL, \
.description = d \
};
#include "definitions.inc"
int main (int argc, char **argv)
{
printf("events(%d, %d) modules(%d)\n", Timer_10, Timer_5, Module_SSH);
return EXIT_SUCCESS;
}
您必须:
- 在运行时分配 ID,
- 手动分配 ID
- 或者将所有事件和模块定义放在一个地方。
假设您有 a.c
和 b.c
,它们分别包含一些 EventA
和 EventB
定义。由于它们是独立的编译单元,编译器无法为它们分配 non-overlapping id。编译 b.c
,它甚至不知道还有另一个 a.c
已经分配了 id 1
。
对于第一个,有一个像这样的 RegisterEvent
函数:
void RegisterEvent(Event* event){
static int nextEventId = 0;
event->eventId = nextEventId;
}
并为您需要的每个 Event
调用它。
第二个很明显,但是乏味且容易出错。
对于第三种解决方案,您可以使用X macro。
X-list 您的所有活动:
#define EventList \
Event(FirstEvent, "FirstEvent") \
Event(Timer_1, "Timer 1 hZ") \
...
Event(Timer_5, "Timer 5 hZ")
现在,在 header 中您要声明所有事件(例如,events.h
):
#define Event(name, desc) EventID ## name,
enum EventID{
EventIDZero = 0,
EventList
EventIDCount
};
#undef Event
#define Event(name, desc) \
extern Event name;
EventList
#undef Event
并且在您的事件定义所在的单个编译单元中(例如,events.c
):
#include "events.h"
#define Event(name, desc) \
Event name = {.eventId = EventID ## name, .data = 0, .description = desc };
EventList
#undef Event
宏扩展后,events.c
看起来像(为了便于阅读而略作编辑):
enum EventID{
EventIDZero = 0,
EventIDFirstEvent, EventIDTimer_1, EventIDTimer_5,
EventIDCount
};
extern Event FirstEvent;
extern Event Timer_1;
extern Event Timer_5;
Event FirstEvent = {.eventId = EventIDFirstEvent, .data = 0, .description = "FirstEvent" };
Event Timer_1 = {.eventId = EventIDTimer_1, .data = 0, .description = "Timer 1 hZ" };
Event Timer_5 = {.eventId = EventIDTimer_5, .data = 0, .description = "Timer 5 hZ" };
模块也是如此。