Click here to Skip to main content
15,879,095 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
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
C++
#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];
};

//gcc __attribute__
#define DECLARE_HANDLER(msg_name,func) __attribute__((section("my_msg_handler"))) \
Handler_t msg_name##_handler={\
    #msg_name,\
    func\
};

//dispath
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;
}
/************* End of msg dispath frame *******************/
/**********************************************************/



/************************     test    ********************/
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;
}
/************************     test end *******************/

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:
C++
#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;
}
/************* End of msg dispath frame *******************/
/**********************************************************/



/************************     test    ********************/
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;
}
Posted
Updated 1-Jan-24 16:44pm
v3

 
Share this answer
 
Out of curiosity: what are you doing that you need to do that?
 
Share this answer
 
Comments
Yount_0701 1-Jan-24 22:46pm    
Without message registration and the message queue management , the coding job would be a little easier. It's basically useful for some code chunk with a lot of switch...case or if/else caluse.
Bruno van Dooren 3-Jan-24 8:38am    
Ok, but the pragma directives you mentioned only change where exactly in the binary pe image, certain pieces of compiled code are stored. What I do not yet understand is how the exact layout of the compiled code in the executable changes the coding job.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900