Вызов некоторых функций перед main в C - PullRequest
6 голосов
/ 03 февраля 2011

Я хотел бы сделать кое-что перед функцией main. У меня есть несколько исходных файлов. В каждом файле есть некоторая работа, которую необходимо выполнить до main. Это не было проблемой в C ++, но проблематично в C.

В C ++ это можно сделать двумя способами:

  1. Использование конструктора глобального класса / структуры.
  2. Вызов функции для глобальной переменной

Например, static const int __register_dummy_ = __AddRegisterMetaInfo(...);

Однако в Си оба пути невозможны. Очевидно, что нет конструктора. Итак, первый вариант по своей сути невозможен.

Я думал, что второй вариант возможен, но не скомпилирован в C (я тестировал только с Visual C ++. Он дает C2099 .). C допускает только константу неавтоматической переменной.

Есть ли способ вызвать некоторые функции перед main?


РЕДАКТИРОВАТЬ : Кажется, многие люди просто неправильно поняли, что я действительно хотел сделать. Извините за написание этого вопроса в упрощенном виде.

Что мне нужно было сделать, это реализовать своего рода информационную функцию класса времени выполнения C ++, точно так же, как подход MFC . При таком подходе мне нужно получить некоторую информацию из всего исходного кода. Например, скажем, каждый исходный файл имеет определение класса, и я хотел бы видеть всю информацию (например, имена классов и родительский класс). Самый простой способ - поместить статический конструктор в каждый файл, и каждый конструктор получает доступ к глобальной структуре данных и регистрирует свою информацию. Но я также хотел найти способ реализовать аналогичную вещь в C. Поэтому простой вызов pre_main_job в main не может быть ответом для меня.

Обратите внимание, что это злоупотребление статическим конструктором также можно найти в наборе компиляторов LLVM. Каждая функция оптимизации / анализа реализована в виде прохода. Все эти проходы регистрируются через статический конструктор.

Ответы [ 4 ]

11 голосов
/ 03 февраля 2011

Для ряда решений, относящихся к компилятору, вы можете взглянуть на файл fips_premain.c из дистрибутива OpenSSL (вы можете просмотреть его онлайн в нескольких местах, например, здесь ).

Часть, специфичная для MSVC, выглядит примерно так (FINGERPRINT_premain - функция, выполняемая до main):

# ifdef _WINDLL
  __declspec(dllexport) /* this is essentially cosmetics... */
# endif
  void FINGERPRINT_premain(void);
  static int premain_wrapper(void) { FINGERPRINT_premain(); return 0; }
# ifdef _WIN64
# pragma section(".CRT$XCU",read)
  __declspec(allocate(".CRT$XCU"))
# else
# pragma data_seg(".CRT$XCU")
# endif
  static int (*p)(void) = premain_wrapper;
  /* This results in pointer to premain to appear in .CRT segment,
   * which is traversed by Visual C run-time initialization code.
   * This applies to both Win32 and [all flavors of] Win64. */
# pragma data_seg()
5 голосов
/ 03 февраля 2011

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

4 голосов
/ 03 февраля 2011

Предполагая, что вы не смешиваете C ++ с вашим C ... (потому что тогда вы могли бы создавать статические конструкторы для своего класса c ++, что, возможно, то, что вы просите!)

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

Некоторые встраиваемые платформы предоставляют типы процедур _pre_main() и _post_main(). Но это нестандартно, я думаю.

Действительно, ваша главная точка входа, ну, main()!

Если вы контролируете Makefile, вы можете заставить main быть чем-то другим, с чем-то вроде

gcc app.c -Dmain=not_really_main

А затем ссылку в вашем реальном main(), чтобы позвонить not_really_main().


edit: еще один подход: компоновщик gcc имеет переменную ENTRY, которая выполняется первым, обычно crt0. Опять же, это довольно тяжелый вес, и вам придется достаточно глубоко понимать платформу, чтобы ее реализовать, но это еще одно место, где вы можете "подорвать основную".

3 голосов
/ 03 февраля 2011

(я знаю, это не прямой ответ на исходный вопрос; однако, это ответ для того, кто ищет способ выполнить код до содержимого main)

Я слышал о лучшей идее - такой, которая даже переносима и предсказуема в поведении . Делайте то, что вы хотите сделать «до main» в начале функции main (или вызывайте функцию, которая делает то, что вы хотите в начале main).

Если вы контролируете код, то (на самом деле!) Нет необходимости в хрупких и часто не поддерживаемых взломах, подобных тем, которые вы предлагали (или вводили).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...