Skip to main content
 首页 » 编程设计

C语言利用 constructor 属性完成 module_init() 设计模式

2022年07月19日21jillzhang

C/C++应用程序

一、简介

1. __attribute__语法格式为:__attribute__ (( attribute-list ))

若函数被设定为 constructor 属性,则该函数会在 main() 函数执行之前被自动的执行。类似的,若函数被设定为 destructor 属性,则该函数会在 main() 函数执行之后或者 exit() 被调用后被自动的执行。

2. 当存在多个 __attribute__((constructor)) 修饰的函数时,也不用持锁,因为是单线程执行的。

3. 还可以使用 __attribute__((constructor(prio))) 指定优先级,从而决定调用次序,优先级prio取值范围是 0--65535,其中 0--100 是预留的,不能使用,优先级数值越小优先级越高,越优先被执行调用。只要指定了优先级,就算是指定的优先级是65535也还是会比没有指定优先级的先调用。

二、 测试例子

1. C程序

#include<stdio.h> 
 
__attribute__((constructor)) void before_main()   
{   
   printf("before main.\n");   
}   
   
__attribute__((destructor)) void after_main()   
{   
   printf("after main.\n");   
}   
   
int main()   
{   
   printf("in main.\n");   
   return 0;   
} 
 
/* 
//执行结果: 
$ ./pp 
before main. 
in main. 
after main. 
*/

2. C++程序

#include<iostream> 
 
using namespace std; 
 
 
__attribute__((constructor)) void before_main() // void 在前后都行 
{   
    //cout<<"Before Main"<<endl;  //注释掉就不 Segmentation fault 了。 
    int i; 
    i++; 
} 
 
__attribute__((destructor)) void after_main()   
{   
    cout<<"After Main"<<endl;   
} 
 
 
class AAA{   
public:   
    AAA(){   
        cout<<"AAA construct"<<endl;   
    }      
    ~AAA(){   
        cout<<"AAA destructor" <<endl;   
    }      
}; 
 
AAA A; //全局类对象 
 
 
int main()   
{   
    cout<<"in main"<<endl;   
    return 0;   
} 
 
/* 
执行结果: 
$ ./pp 
AAA construct 
in main 
AAA destructor 
After Main 
*/

注:测试发现,C++中 __attribute__((constructor)) 修饰的函数中不能执行 cout<<"..."<<endl 语句,否则会 Segmentation fault


三、实现类似Linux内核中 module_init() 的设计模式

1. 实现

Linux内核中 module_init() 是通过链接器脚本实现的,用户空间程序可以使用 constructor 属性实现。

(1) core.c

#include <stdio.h> 
#include <stdlib.h> 
#include "core.h" 
 
struct function *g_functions[FUNC_NUM] = {NULL}; 
 
static int module_init() 
{ 
    int i, ret = 0; 
 
    for (i = 0; i < ARRAY_SIZE(g_functions); i++) { 
        if (g_functions[i] && g_functions[i]->init) { 
            ret = g_functions[i]->init(); 
        } 
    } 
 
    return ret; 
} 
 
static int module_exit() 
{ 
    int i; 
 
    for (i = 0; i < ARRAY_SIZE(g_functions); i++) { 
        if (g_functions[i] && g_functions[i]->release) { 
            g_functions[i]->release(); 
            g_functions[i] = NULL; 
        } 
    } 
 
    return 0; 
} 
 
static int module_do_function(int code) 
{ 
    int i, ret = 0; 
 
    for (i = 0; i < ARRAY_SIZE(g_functions); i++) { 
        if (g_functions[i] && g_functions[i]->id == code) { 
            ret = g_functions[i]->execute(code); 
        } 
    } 
 
    return ret; 
} 
 
 
int main(int argc, char *argv[]) 
{ 
    int ret, code = 0; 
 
    if (argc == 2) { 
        code = atoi(argv[1]); 
    } 
 
    module_init(); 
    module_do_function(code); 
    module_exit(); 
}

(2) core.h

#define FUNC_NUM 16 
 
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a)) 
 
struct function { 
    int id; 
    int (*init)(void); 
    int (*execute)(int code); 
    void (*release)(void); 
}; 
 
extern struct function *g_functions[FUNC_NUM]; 
 
 
#define function_register(name)                                    \ 
void __attribute__((constructor)) function_##name##_register(void) \ 
{                                                                  \ 
    int i;                                                         \ 
    for (i = 0; i < ARRAY_SIZE(g_functions); i++) {                \ 
        if (!g_functions[i]) {                                     \ 
            g_functions[i] = &func_##name;                         \ 
            break;                                                 \ 
        }                                                          \ 
    }                                                              \ 
    printf("%s, id=%d.\n", __func__, func_##name.id);              \ 
}

(3) camera.c

#include <stdio.h> 
#include "core.h" 
 
#define CAMERA_FUN_ID 1 
 
 
static int camera_init(void) { 
    int ret = 0; 
 
    printf("camera_init called.\n"); 
 
    return ret; 
} 
 
static int camera_execute(int code) { 
    int ret = 0; 
 
    printf("camera_execute called.\n"); 
 
    return ret; 
} 
 
static void camera_release(void) { 
    printf("camera_release called.\n"); 
} 
 
static struct function func_camera = { 
    .id = CAMERA_FUN_ID, 
    .init = camera_init, 
    .execute = camera_execute, 
    .release = camera_release, 
}; 
 
function_register(camera);

(4) led.c

#include <stdio.h> 
#include "core.h" 
 
#define LED_FUN_ID 2 
 
 
static int led_init(void) { 
    int ret = 0; 
 
    printf("led_init called.\n"); 
 
    return ret; 
} 
 
static int led_execute(int code) { 
    int ret = 0; 
 
    printf("led_execute called.\n"); 
 
    return ret; 
} 
 
static void led_release(void) { 
    printf("led_release called.\n"); 
} 
 
static struct function func_led = { 
    .id = LED_FUN_ID, 
    .init = led_init, 
    .execute = led_execute, 
    .release = led_release, 
}; 
 
function_register(led);

2. 测试

$ gcc *.c -o pp 
 
$ ./pp 
function_camera_register, id=1. 
function_led_register, id=2. 
camera_init called. 
led_init called. 
camera_release called. 
led_release called. 
 
$ ./pp 1 
function_camera_register, id=1. 
function_led_register, id=2. 
camera_init called. 
led_init called. 
camera_execute called. 
camera_release called. 
led_release called.

3. 若需要再添加其它命令,值需要添加一个文件并注册即可,不用改原有文件。


本文参考链接:https://www.cnblogs.com/hellokitty2/p/15612442.html