【C语言】__attribute__((constructor)) 和 __attribute__((destructor))详细解析
__attribute__((constructor))
和 __attribute__((destructor))
是 GCC(GNU Compiler Collection)中的两个特殊属性,用于在程序初始化或终止时自动执行特定的函数。它们允许开发者控制函数在程序生命周期中的执行顺序。下面详细介绍其用法及优先级控制的内容:
1. __attribute__((constructor))
-
定义:当一个函数被标记为
__attribute__((constructor))
时,该函数会在main()
函数之前自动执行,即在程序初始化阶段执行。 -
用法:
#include <stdio.h> void __attribute__((constructor)) init_function() { printf("This function is called before main()\n"); } int main() { printf("This is inside main()\n"); return 0; }
输出:
This function is called before main() This is inside main()
-
优先级控制:可以通过给
constructor
属性传递一个整数参数来设置优先级,数字越小,函数越早执行。默认为priority = 100
,也就是说,所有没有显式设置优先级的constructor
函数都会按照代码中的出现顺序执行,而设置了优先级的函数则按照从低到高的顺序执行。例如:
#include <stdio.h> void __attribute__((constructor(101))) first_function() { printf("First function\n"); } void __attribute__((constructor(102))) second_function() { printf("Second function\n"); } void __attribute__((constructor(50))) third_function() { printf("Third function (highest priority)\n"); } int main() { printf("This is inside main()\n"); return 0; }
输出:
Third function (highest priority) First function Second function This is inside main()
在这个例子中,
third_function
设置了优先级为50
,比其他函数优先级高,因此首先执行。first_function
和second_function
分别为101
和102
,它们按照优先级顺序执行。
2. __attribute__((destructor))
-
定义:与
constructor
相对,__attribute__((destructor))
标记的函数会在main()
函数执行结束后自动执行,即程序终止时执行,用于清理资源。 -
用法:
#include <stdio.h> void __attribute__((destructor)) cleanup_function() { printf("This function is called after main()\n"); } int main() { printf("This is inside main()\n"); return 0; }
输出:
This is inside main() This function is called after main()
-
优先级控制:与
constructor
类似,destructor
也可以通过传递参数控制优先级,数字越小,函数越早执行。默认优先级为100
。这对于确保某些清理操作比其他操作先执行是很有用的。例如:
#include <stdio.h> void __attribute__((destructor(102))) first_cleanup() { printf("First cleanup\n"); } void __attribute__((destructor(50))) second_cleanup() { printf("Second cleanup (highest priority)\n"); } int main() { printf("This is inside main()\n"); return 0; }
输出:
This is inside main() Second cleanup (highest priority) First cleanup
在这里,
second_cleanup
由于优先级较高(50),会在first_cleanup
之前执行。
3. 典型应用场景
-
资源初始化和清理:通过设置优先级,可以确保程序中依赖于某些资源的初始化函数先于其他函数执行,并且清理函数也可以有序执行。例如:
constructor
函数可以用于分配全局资源、初始化库或加载配置。destructor
函数可以用于释放全局资源、保存状态或关闭文件/数据库连接等。
-
动态链接库中的应用:在动态链接库中,
constructor
和destructor
常用于确保在加载库时初始化全局状态,在卸载库时清理全局资源。
4. 注意事项
-
不可过度使用:虽然
constructor
和destructor
属性使得代码的自动执行变得方便,但过多使用可能导致程序的控制流不太清晰,增加维护复杂度。建议仅在资源初始化和清理等明确的场景中使用。 -
跨平台兼容性:这些属性属于 GCC 扩展,其他编译器(如 MSVC)可能不支持,因此如果需要跨平台兼容,需小心处理。
-
执行时机:
constructor
函数的执行时机是在动态链接器完成库的加载后、但在main()
之前;而destructor
函数的执行时机是在main()
或共享库的其他代码完成执行后、在程序终止之前。
5. 总结
-
__attribute__((constructor))
:标记的函数在main()
函数之前执行,适合用于程序初始化。- 可以通过设置优先级,控制多个初始化函数的执行顺序,优先级数值越小,函数执行得越早。
-
__attribute__((destructor))
:标记的函数在main()
函数之后、程序终止时执行,适合用于清理资源。- 同样可以通过设置优先级,控制多个清理函数的执行顺序,优先级数值越小,函数执行得越早。