GNU complier support the __attribute__(section...) features which could put method or variables into specified sections and make code simple .
It seems use some complier keywords to finish the data bindings and message mappings.
What I have tried:
The following code is a sample
#include <stdio.h>
#include <string.h>
#include <stdint.h>
typedef struct _handler{
const char* msg_name;
void*(*func)(void*,size_t);
}Handler_t;
struct msg{
char msg_name[32];
size_t msg_len;
uint8_t msg_data[0];
};
#define DECLARE_HANDLER(msg_name,func) __attribute__((section("my_msg_handler"))) \
Handler_t msg_name##_handler={\
#msg_name,\
func\
};
extern Handler_t __start_my_msg_handler;
extern Handler_t __stop_my_msg_handler;
int dispath(struct msg* msg) {
int i;
Handler_t* handler=&__start_my_msg_handler;
for(i=0;i<&__stop_my_msg_handler-&__start_my_msg_handler;i++) {
if(!strncmp(msg->msg_name,handler[i].msg_name,32)) {
handler[i].func(msg->msg_data,msg->msg_len);
break;
}
}
return 0;
}
void* handler_test(void* msg_data,size_t len) {
printf("%s msg data:%s,msg length:%d\n",__func__,(char*)msg_data,len);
return 0;
}
DECLARE_HANDLER(test,handler_test);
int main(void) {
uint8_t _msg[64]={0};
struct msg* my_msg=(struct msg*)_msg;
strcpy(my_msg->msg_name,"test");
strcpy((char*)my_msg->msg_data,"Hello , My msg test.");
my_msg->msg_len=strlen((char*)my_msg->msg_data)+1;
dispath(my_msg);
return 0;
}
How to make it work in MSVC?
MSVC CAN do this. There is a complier switch __declspec(allocate(`seg_name`)) to specify the segment of global variables. And if the `seg_name` contains '$', the linker would automatically merge these segments sorted by the name sequence. So if you name 2 segments , then there would be the top and the bottom bounds, which could help you to access the variables of the segments.
Here is my fixed code:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#define MSG_START "my_msg_handler"
#define MSG_STOP "my_msg_handler$zone"
#pragma section(MSG_START)
#pragma section(MSG_STOP)
typedef struct _handler{
const char* msg_name;
void*(*func)(void*,size_t);
}Handler_t;
struct msg{
char msg_name[32];
size_t msg_len;
uint8_t msg_data[0];
};
#define SECTION_ALLOCATE(flag) __declspec(allocate(flag))
SECTION_ALLOCATE(MSG_START) __declspec(selectany) Handler_t __start_my_msg_handler[];
SECTION_ALLOCATE(MSG_STOP) __declspec(selectany) Handler_t __stop_my_msg_handler[];
#define DECLARE_HANDLER(msg_name,func) \
SECTION_ALLOCATE(MSG_START) Handler_t msg_name##_handler={\
#msg_name,\
func\
};
int dispath(struct msg* msg) {
int i;
Handler_t* handler=&__start_my_msg_handler[0];
Handler_t* stop=&__stop_my_msg_handler[0];
for(i=0;i<stop-handler;i++) {
if(!strncmp(msg->msg_name,handler[i].msg_name,32)) {
handler[i].func(msg->msg_data,msg->msg_len);
break;
}
}
return 0;
}
void* handler_test(void* msg_data,size_t len) {
printf("%s msg data:%s,msg length:%d\n",__func__,(char*)msg_data,len);
return 0;
}
DECLARE_HANDLER(test,handler_test)
int main(void) {
uint8_t _msg[64]={0};
struct msg* my_msg=(struct msg*)_msg;
strcpy(my_msg->msg_name,"test");
strcpy((char*)my_msg->msg_data,"Hello , My msg test.");
my_msg->msg_len=strlen((char*)my_msg->msg_data)+1;
dispath(my_msg);
return 0;
}