Вызов функции непосредственно перед main

Можно ли зарегистрировать функцию для запуска немедленно перед вводом main? Я знаю, что все глобальные объекты создаются до ввода main, поэтому я мог бы поместить код в конструктор глобального объекта, но это не гарантирует какой-либо определенный порядок. Что я хотел бы сделать, так это поместить код регистрации в конструктор, но, увы, я не знаю, что туда поместить :) Я предполагаю, что это сильно зависит от системы?


person fredoverflow    schedule 07.03.2011    source источник
comment
Можете ли вы поместить код для запуска непосредственно перед вводом main в main(), а затем создать вторую функцию, the_real_main(), которая вызывается оттуда? Может быть, это обман.   -  person James McNellis    schedule 07.03.2011
comment
Утверждение: «цитата» не гарантирует какой-либо конкретный заказ‹/цитата› является слишком общим и, следовательно, не совсем правильным. Порядок построения единицы компиляции хорошо определен как порядок объявления. Просто порядок между единицами компиляции не определен четко (так как это зависит от компоновщика).   -  person Martin York    schedule 07.03.2011
comment
Что именно вы пытаетесь сделать с помощью этой функции, которая не может быть выполнена как первая функция, вызываемая в main?   -  person RedX    schedule 07.03.2011


Ответы (4)


Если вы используете gcc, вы можете использовать атрибут constructor для функции, чтобы она вызывалась до main (см. документацию для более подробной информации).

constructor

destructor

Атрибут constructor вызывает автоматический вызов функции до того, как выполнение войдет в main (). Точно так же атрибут destructor вызывает автоматический вызов функции после завершения main () или вызова exit (). Функции с этими атрибутами полезны для инициализации данных, которые будут неявно использоваться во время выполнения программы.

person Sylvain Defresne    schedule 07.03.2011

Не уверен, что это именно то, что вы хотите... Но это должно сработать.

int main() {
  static int foo = registerSomething();
}

Лучше явно вызывать такие функции регистрации либо в main, либо при первом доступе (но init при первом доступе может вызвать проблемы, если вы используете многопоточность).

person Erik    schedule 07.03.2011
comment
Это не сильно отличается от простого использования registerSomething() без статической переменной. - person James McNellis; 07.03.2011
comment
Нет, но можно (с некоторым принуждением) сказать, что он логически выполняется перед кодом в основном :) - person Erik; 07.03.2011

Я предполагаю здесь, но:

  1. Вы хотите зарегистрировать что-то в другой единице компиляции
  2. Вы столкнулись с проблемой регистрации, потому что глобальные переменные, в которые вы сохраняете регистрации, еще не созданы.

C++ определяет, что статическая функция инициализируется за некоторое время до первого обращения к ней, поэтому вы можете обойти это, как показано ниже.

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;
    }
};
person Dark Falcon    schedule 07.03.2011

Цель

Допустим, вам нужно следующее:

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");
}

Реализация

Версия C++ — статическая переменная + конструктор:

// 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 — статическая переменная + функция

// ... 

// 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 { ... }

Примечания

    #define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b)
    #define BOOST_PP_CAT_I(a, b) a ## b
person Dave Dopson    schedule 12.07.2013
comment
ой. Моя первая попытка провалилась. StaticExecute__##__LINE превращается в StaticExecute__LINE, а НЕ в __StaticExecute__247, как я ожидал. Исправление с помощью какой-то сумасшедшей магии, украденной у Boost. - person Dave Dopson; 13.07.2013