我一直在阅读一本详细介绍C/C++构建过程的书,其中提到有一个GNU扩展允许您在main()启动之前指定要运行的函数。对于这样一个函数,有哪些好的用例?这与main()启动后第一件事做有什么区别?我更追求理论上的答案,而不是任何具体的代码。
l7mqbcuq1#
库初始化其全局状态非常有用。没有它,应用程序必须从main()调用库的初始化函数。标准C运行时中的示例是stdin、stdout和stderr的初始化。虽然这些都是由C运行时本身初始化的,但是您引用的特性允许用户编写的库进行类似的初始化。C++可能使用它来调用全局变量的构造函数。
main()
stdin
stdout
stderr
iqxoj9l92#
您所描述的扩展不适用于正常使用。正如你所说的那样,在程序开始时调用例程和在程序开始时调用例程没有区别(除非你想在一些标准初始化完成之前)这意味着在某些库的情况下,需要其他库之前没有初始化,你需要在C运行时初始化时运行main()的初始化代码。您描述的特性不是GNU特定的,而是包含在ELF二进制格式中。ELF提供了一个包含两个入口点init和fini的加载模块,在加载时首先调用,在卸载前最后调用。此外,还有另一个入口点(通常称为_start,但这可以由链接器更改)作为程序的入口点,通常保留给c运行时模块,结束调用main()。一些库提供了一个init函数,在库加载时调用,以避免强迫用户自己调用一些初始化例程,并确保无论如何都能得到一个正确初始化的库。请记住,这个特性不是在程序加载时完成的,而是在库加载时完成的,但是ELF将程序视为只有一个入口点的库。链接器/加载器通常会选择不同的init例程来调用,其顺序允许库依赖关系被正确初始化(依赖于B的库A使B的init例程在A的init之前被调用)
init
fini
_start
3htmauhk3#
我用它来初始化静态存储变量,这些变量放在启动代码没有初始化的段中。当你从主代码返回时,也会调用一些代码(用于你的清理操作)
3条答案
按热度按时间l7mqbcuq1#
库初始化其全局状态非常有用。没有它,应用程序必须从
main()
调用库的初始化函数。标准C运行时中的示例是
stdin
、stdout
和stderr
的初始化。虽然这些都是由C运行时本身初始化的,但是您引用的特性允许用户编写的库进行类似的初始化。C++可能使用它来调用全局变量的构造函数。
iqxoj9l92#
您所描述的扩展不适用于正常使用。
正如你所说的那样,在程序开始时调用例程和在程序开始时调用例程没有区别(除非你想在一些标准初始化完成之前)这意味着在某些库的情况下,需要其他库之前没有初始化,你需要在C运行时初始化时运行
main()
的初始化代码。您描述的特性不是GNU特定的,而是包含在ELF二进制格式中。ELF提供了一个包含两个入口点init
和fini
的加载模块,在加载时首先调用,在卸载前最后调用。此外,还有另一个入口点(通常称为_start
,但这可以由链接器更改)作为程序的入口点,通常保留给c运行时模块,结束调用main()
。一些库提供了一个
init
函数,在库加载时调用,以避免强迫用户自己调用一些初始化例程,并确保无论如何都能得到一个正确初始化的库。请记住,这个特性不是在程序加载时完成的,而是在库加载时完成的,但是ELF将程序视为只有一个入口点的库。链接器/加载器通常会选择不同的init
例程来调用,其顺序允许库依赖关系被正确初始化(依赖于B的库A使B的init
例程在A的init
之前被调用)3htmauhk3#
我用它来初始化静态存储变量,这些变量放在启动代码没有初始化的段中。
当你从主代码返回时,也会调用一些代码(用于你的清理操作)