Подтвердить что ты не робот

В С++ основная функция - это точка входа в программу, как я могу изменить ее на другую функцию?

Мне был задан вопрос об интервью, чтобы изменить точку входа программы C или С++ с main() на любую другую функцию. Как это возможно?

4b9b3361

Ответ 1

В стандартном C (и, я считаю, С++), вы не можете, по крайней мере, не для размещенной среды (но см. ниже). Стандарт указывает, что отправной точкой для кода C является main. Стандарт (c99) не оставляет возможности для аргумента:

5.1.2.2.1 Запуск программы: (1) Функция, вызванная при запуске программы, называется main.

Что это. Затем он немного размышляет о параметрах и возвращает значения, но там действительно нет возможности изменить имя.

Это для размещенной среды. Стандарт также позволяет использовать автономную среду (то есть без ОС, для таких вещей, как встроенные системы). Для автономной среды:

В автономной среде (в которой выполнение программы C может иметь место без какой-либо выгоды от операционной системы), имя и тип функции, вызываемой при запуске программы, определяются в соответствии с реализацией. Любые библиотечные средства, доступные для автономной программы, отличные от минимального набора, требуемого в соответствии с разделом 4, определяются реализацией.

Вы можете использовать "обман" в реализациях C, чтобы вы могли выглядеть так: main не является точкой входа. Это на самом деле то, что ранние разработчики Windows сделали, чтобы отметить WinMain в качестве начальной точки.


Первый способ: компоновщик может включать некоторый код предварительного запуска в файле типа start.o, и именно эта часть кода запускает настройку среды C, а затем вызывает main. Нет ничего, что могло бы помешать вам заменить это тем, что называет bob.


Второй способ: некоторые компоновщики предоставляют эту опцию с помощью командной строки, поэтому вы можете изменить ее без перекомпиляции кода запуска.


Третий способ: вы можете связать этот фрагмент кода:

int main (int c, char *v[]) { return bob (c, v); }

а затем ваша точка входа для вашего кода выглядит как bob, а не main.


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

Я бы спросил у интервьюера: зачем вам это делать?

Ответ 2

Точка входа на самом деле является функцией _start (реализована в crt1.o).

Функция _start подготавливает аргументы командной строки, а затем вызывает main(int argc,char* argv[], char* env[]), вы можете изменить точку входа с _start на mystart, установив параметр компоновщика:

g++ file.o -Wl,-emystart -o runme

Конечно, это замена точки входа _start поэтому вы не получите аргументы командной строки:

void mystart(){

}

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

Ответ 3

Из стандартных документов С++ 3.6.1 Основная функция,

Программа должна содержать глобальную функцию main, которая является назначенным началом программы. Определяется реализациейтребуется ли программа в автономной среде для определения основной функции.

Итак, он зависит от от вашего компилятора/компоновщика...

Ответ 4

Если вы находитесь на VS2010, this может дать вам некоторую идею

Как легко понять, это не санкционировано стандартом С++ и попадает в область "специфичного для реализации поведения".

Ответ 5

Это очень умозрительно, но у вас может быть статический инициализатор вместо основного:

#include <iostream>

int mymain()
{
    std::cout << "mymain";
    exit(0);
}

static int sRetVal = mymain();

int main()
{
    std::cout << "never get here";
}

Вы могли бы даже сделать это 'подобным Java', помещая материал в конструктор:

#include <iostream>

class MyApplication
{
public:
    MyApplication()
    {
        std::cout << "mymain";
        exit(0);
    }
};

static MyApplication sMyApplication;

int main()
{
    std::cout << "never get here";
}

Сейчас. Интервьюер мог бы подумать об этом, но я лично никогда не использовал бы их. Причины:

  • Это нетрадиционно. Люди этого не поймут, нетривиально найти точку входа.
  • Порядок статической инициализации является недетерминированным. Вставьте другую статическую переменную, и вы никогда не будете сейчас, если она будет инициализирована.

Тем не менее, я видел, что он используется в производстве вместо init() для инициализаторов библиотеки. Предостережение заключается в том, что в Windows (из опыта) ваша статика в DLL может или не может быть инициализирована в зависимости от использования.

Ответ 6

Измените объект crt, который фактически вызывает функцию main(), или предоставит свой собственный (не забудьте отключить привязку обычного).

Ответ 7

С gcc объявите функцию с атрибутом ((конструктор)), и gcc выполнит эту функцию перед любым другим кодом, включая main.

Ответ 8

Для систем на основе Solaris я нашел this. Вы можете использовать раздел .init для всех платформ, которые я предполагаю:

   pragma init (function [, function]...)

Источник:

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

Ответ 9

Это очень просто:

Как вам следует знать, когда вы используете константы в c, компилятор выполняет своего рода "макрос", изменяя имя константы для соответствующего значения.

просто включите аргумент #define в начало вашего кода с именем функции запуска, за которым следует имя main:

Пример:

#define my_start-up_function (main)

Ответ 10

Я думаю, что легко удалить нежелательный символ main() из объекта перед связыванием.

К сожалению, опция точки входа для g++ не работает для меня (двоичный файл падает перед входом в точку входа). Поэтому я удаляю нежелательную точку входа из объектного файла.

Предположим, у нас есть два источника, которые содержат функцию точки входа.

  1. target.c содержит main(), которую мы не хотим.
  2. our_code.c содержит testmain(), мы хотим быть точкой входа.

После компиляции (опция g++ -c) мы можем получить следующие объектные файлы.

  1. target.o, который содержит main(), который мы не хотим.
  2. our_code.o, который содержит testmain(), мы хотим быть точкой входа.

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

objcopy --strip-symbol = main target.o

Мы также можем переопределить testmain() и main(), используя objcopy.

objcopy --redefine-sym testmain = main our_code.o

И тогда мы можем связать их обоих в двоичный файл.

g++ target.o our_code.o -o our_binary.bin

Это работает для меня. Теперь, когда мы запускаем our_binary.bin точкой входа является our_code.o:main() который ссылается на our_code.c::testmain().

Ответ 11

В окнах есть другой (довольно неортодоксальный) способ изменить точку входа в программу: TLS. См. Дополнительные пояснения: http://isc.sans.edu/diary.html?storyid=6655

Ответ 12

Да, Мы можем изменить имя главной функции на любое другое имя, например. Начать, bob, rem и т.д.

Как компилятор знает, что он должен искать main() во всем коде?

В программировании ничего нет. кто-то проделал определенную работу, чтобы он выглядел автоматически для нас.

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

мы можем изменить название main на что-нибудь еще, например. Боб, а затем компилятор будет искать только Bob().

Ответ 13

Изменение значения в настройках компоновщика переопределит точку входа. то есть приложения MFC используют значение "Windows (/SUBSYSTEM: WINDOWS)", чтобы изменить точку входа с main() на CWinApp :: WinMain().

Right clicking on solution > Properties > Linker > System > Subsystem > Windows (/SUBSYSTEM:WINDOWS)

...

Очень практическая выгода для изменения точки входа:

MFC - это фреймворк, которым мы пользуемся для написания приложений для Windows на C++. Я знаю это древнее, но моя компания поддерживает его по наследству! Вы не найдете main() в коде MFC. MSDN говорит, что точка входа - это WinMain(). Таким образом, вы можете переопределить WinMain() вашего базового объекта CWinApp. Или большинство людей переопределяют CWinApp :: InitInstance(), потому что базовый WinMain() будет вызывать его.

Отказ от ответственности: я использую пустые скобки для обозначения метода, не заботясь о том, сколько аргументов.