Is is possible to register a function to be run immediately before main
is entered? I know that all global objects are created before entering main
, so I could put the code in the constructor of a global object, but that does not guarantee any particular order. What I would like to do is put some registration code into the constructor, but alas, I don't know what to put there :) I guess this is highly system-specific?
问题:
回答1:
If you're using gcc
, you can use the constructor
attribute on a function to have it called before main
(see the documentation for more details).
constructor
destructor
The
constructor
attribute causes the function to be called automatically before execution entersmain ()
. Similarly, thedestructor
attribute causes the function to be called automatically aftermain ()
has completed orexit ()
has been called. Functions with these attributes are useful for initializing data that will be used implicitly during the execution of the program.
回答2:
Not sure this is exactly what you want... But it should do the job.
int main() {
static int foo = registerSomething();
}
It's better to explicitly calls such registration functions, either in main or on first access (but first access init could pose issues if you're multithreaded).
回答3:
I am guessing here but:
- You want to register something in a different compilation unit
- You ran into a problem with the registration because the global variables in which you're saving registrations were not yet constructed.
C++ defines that a function-static is initialized sometime before it is first accessed, so you can work around it in the way shown below.
typedef std::map<std::string, std::string> RegistrationCache;
RegistrationCache& get_string_map()
{
static RegistrationCache cache;
return cache;
}
class Registration
{
Registration(std::string name, std::string value)
{
get_string_map()[name] = value;
}
};
回答4:
Goal
Let's say you want the following:
STATIC_EXECUTE {
printf("This probably prints first"\n");
}
STATIC_EXECUTE {
printf("But order isn't guaranteed in the language spec, IIRC"\n");
}
int main(int argc, char **argv) {
printf("This definitely prints last. Buh Bye.\n");
}
Implementation
C++ version - static variable + constructor:
// This is some crazy magic that produces __StaticExecute__247
// Vanilla interpolation of __StaticExecute__##__LINE__ would produce __StaticExecute____LINE__
// I still can't figure out why it works, but it has to do with macro resolution ordering
// If you already have Boost, you can omit this part
#define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b)
#define BOOST_PP_CAT_I(a, b) BOOST_PP_CAT_II(~, a ## b)
#define BOOST_PP_CAT_II(p, res) res
// This avoids repeating the BOOST_PP_CAT 5X
#define STATIC_EXECUTE \
STATIC_EXECUTE_I(BOOST_PP_CAT(__StaticExecute__, __LINE__))
// This is the meat, a static instance of a class whose constructor runs your code
#define STATIC_EXECUTE_I(uniq_name) \
static struct uniq_name { \
uniq_name(); \
} BOOST_PP_CAT(uniq_name, __var); \
uniq_name::uniq_name() // followed by { ... }
C version - static variable + function
// ...
// The meat: a static variable initialized from a function call
#define STATIC_EXECUTE_I(uniq_name) \
static void uniq_name (); \
static int BOOST_PP_CAT(uniq_name, __var) = \
(uniq_name(), 0); \
static void uniq_name() // followed by { ... }
Notes
IMHO, the C++ version is slightly more elegant. In-theory, it consumes slightly less space. Otherwise, potato, po-tat-oh.
Caveat: I haven't tested the "C" version on a proper C-only compiler. Fingers crossed; post a note if it doesn't work.
Caveat: Compiler portability in general is a tricky thing. I wouldn't be shocked if there's a bug on some other compiler.
The BOOST_PP_CAT code is stolen from boost/preprocessor/cat.hpp. I simplified the implementation, and in the process may have compromised portability. If it doesn't work, try the original (more verbose) implementation, and post a comment below. Or, if you are already using Boost, you can just use their version.
If you are trying to understand the Boost magic, note that (at least for me, and in this scenario), the following also seems to work:
#define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b)
#define BOOST_PP_CAT_I(a, b) a ## b