What kind of operations might one need to do before main()
I came across this question asking how to execute code before main() in C, mentioning there were strategies for C++. I've m开发者_开发问答ostly lived in application space, so executing before main() has never occurred to me. What kind of things require this technique?
"What kind of things require this technique?"
Point of fact: none.
However, there are a lot of useful things you might WANT to do before main for a variety of reasons. For just one practical example, say you have an abstract factory that builds doohickies. You could make sure to build the factory instance, assign it to some special area, and then register the various concrete doohickies to it...yes, you can do that.
On the other hand, if you implement the factory as a singleton and use the facts of global value initialization to "trick" the implementation into registering concrete doohickies before main starts you gain several benefits with very few costs (the fact of using singletons, basically a non-issue here, is pretty much the only one).
For example you:
Don't have to maintain a list of registrations that all must be explicitly called. In fact, you can even declare and define an entire class in private scope, out of sight of anyone, and have it available for use when the program starts.
main() doesn't have to do a bunch of crap with a bunch of objects it doesn't care about.
So, none of this is actually necessary. However, you can reduce coupling and maintenance issues if you leverage the fact that globals are initialized before main begins.
Edit:
Should note here that I've since learned that this isn't guaranteed by the language. C++ only guarantees that zero or constant initialization happens before main. What I talk about in this answer is dynamic initialization. This C++ guarantees happens before the first use of the variable, much like function-local static variables.
Every compiler though seems to do dynamic initialization before main. I thought I ran into one once that did not but I believe the source of the issue was something else.
This technique can be used for library initialization routines or for initializing data that will be used implicitly during the execution of the program.
GCC provides constructor and destructor function attributes that cause a function to be called automatically before execution enters main()
or main()
has completed or exit()
has been called, respectively.
void __attribute__ ((constructor)) my_init(void);
void __attribute__ ((destructor)) my_fini(void);
In the case of library initialization, constructor routines are executed before dlopen()
returns if the library is loaded at runtime or before main()
is started if the library is loaded at load time. When used for library cleanup, destructor routines are executed before dlclose()
returns if the library is loaded at runtime or after exit()
or completion of main()
if the library is loaded at load time.
The only things you could want to do before main
involve global variables, which are bad, and the same things could always be accomplished by lazy initialization (initialization at the point of first use). Of course they'd be much better accomplished by not using global variables at all.
One possible "exception" is the initialization of global constant tables at runtime. But this is a very bad practice, as the tables are not sharable between instances of a library/process if you fill them at runtime. It's much smarter to write a script to generate the static const
tables as a C or C++ source file at build time.
Stuff done before main:
- On x86, the stack pointer register is usually &=0XF3 to make it a multiple of 4 (alignment)
- Static members are initialized
- push argc and argv (and environ if needed)
- call _main =p
g++ 4.4 emits the following before any of my code is emitted. Technically it inserts it into the top of main
before any of my code, but I've seen compilers that use _init
instead of _main
as the entry point:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
# My code follows
Anything that needs to run code to guarantee invariants for your code after main
starts needs to run before main
. Things like global iostreams, the C runtime library, OS bindings, etc.
Now whether you actually need to write code that does such things as well is what everyone else is answering.
If you have a library, it is very convenient to be able to initialise some data, create threads etc. before main() is invoked, and know that a desired state is achieved without burdening and trusting the client app to explicitly call some library initialisation and/or shutdown code. Superficially, this can be achieved by having a static object whose constructor and destructor performs the necessary operations. Unfortunately, multiple static objects in different translation units or libraries will have an undefined order of initialisation, so if they depend upon each other (worse yet, in a cyclic fashion), then they may still not have achieved their initialised state before a request comes in. Similarly, one static object may create threads and call services in another object that aren't yet threadsafe. So, a more structured approach with proper singleton instances and locks is needed for robustness in the face of arbitrary usage, and the whole thing looks much less appealing, though it may still be a net win in some cases.
精彩评论