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. 若需要再添加其它命令,值需要添加一个文件并注册即可,不用改原有文件。