Calling a function immediately before main

穿精又带淫゛_ 提交于 2019-12-03 13:17:47

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 enters main (). Similarly, the destructor attribute causes the function to be called automatically after main () has completed or exit () has been called. Functions with these attributes are useful for initializing data that will be used implicitly during the execution of the program.

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).

I am guessing here but:

  1. You want to register something in a different compilation unit
  2. 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;
    }
};

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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!