Можно ли написать программу без использования функции main ()? - PullRequest
32 голосов
/ 13 августа 2011

Мне постоянно задают этот вопрос в интервью:

Написать программу без использования функции main()?

Один из моих друзей показал мне код с помощью макросов, но я не мог этого понять.

Так что вопрос:

Реально ли написать и скомпилировать программу без main()?

Ответы [ 20 ]

27 голосов
/ 13 августа 2011

Нет, вы не можете, если вы пишете программу в freestanding environment (ядро встроенной среды ОС и т. Д.), Где отправная точка не обязательно должна быть main().Согласно стандарту C ++ main() является отправной точкой любой программы в hosted environment.

Согласно:

C ++ 03 стандарт 3.6.1 Основная функция

1 Программа должна содержать глобальную функцию, называемуюглавная, которая является обозначенным началом программы.Определяется реализацией, требуется ли программе в автономной среде для определения главной функции.[Примечание: в автономной среде запуск и завершение определяются реализацией;автозагрузка содержит выполнение конструкторов для объектов области пространства имен со статической длительностью хранения;Завершение содержит выполнение деструкторов для объектов со статической продолжительностью хранения.


Что такое freestanding Environment & Что такое Hosted Environment?
Существует два видасоответствующих реализаций, определенных в стандарте C ++;hosted и freestanding.

Реализация freestanding - это реализация, предназначенная для программ, которые выполняются без использования операционной системы.
Например: ядро ​​ОС или встроенная среда будут автономной средой.

Программа, использующая возможности операционной системы, обычно находится в hosted implementation.

Из стандарта C ++ 03 Раздел 1.4 / 7:

Автономная реализация - это реализация, в которой выполнение может выполняться без использования операционной системы, и она имеет определенный для реализации набор библиотек, который включает в себя определенные библиотеки поддержки языка.

Далее,
Раздел: 17.4.1.3.2 Отдельно стоящие реализации цитаты:

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

18.1 Types <cstddef>   
18.2 Implementation properties <limits>   
18.3 Start and termination <cstdlib> 
18.4 Dynamic memory management <new> 
18.5 Type identification <typeinfo> 
18.6 Exception handling <exception> 
18.7 Other runtime support <cstdarg>
17 голосов
/ 13 августа 2011

В стандартном C ++ требуется функция main, поэтому вопрос не имеет смысла для стандартного C ++.

Вне стандартного C ++ вы можете, например, написать специальную программу для Windows и использовать одну из пользовательских программ Microsoft.функции запуска (wMain, winMain, wWinmain).В Windows вы также можете написать программу в виде DLL и использовать для ее запуска rundll32.

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

Наконец, вы можете стать умным и возразить, что в соответствии с правилом ODR стандарта main не «используется», поэтому любая программа соответствует требованиям.Ба!Хотя, если бы у интервьюеров не было необычайно хорошего чувства юмора (и они бы не задавали вопрос, если бы имели), они бы не подумали, что это хороший ответ.

15 голосов
/ 13 августа 2011

Пример программы без видимой основной функции.

/* 
    7050925.c 
    $ gcc -o 7050925 7050925.c
*/

#include <stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)

int begin()
{
        printf("How mainless!\n");
}

От: http://learnhacking.in/c-program-without-main-function/

11 голосов
/ 14 августа 2011

main означает точку входа, точку, с которой начнет выполняться ваш код. хотя main не первая функция, которая запускается. Есть еще немного кода, который выполняется до main и подготавливает среду к запуску вашего кода. Затем этот код вызывает main. Вы можете изменить имя функции main, перекомпилировав код файла запуска crt0.c и изменив имя функции main. Или вы можете сделать следующее:

#include <stdio.h>

extern void _exit (register int code);

_start()
{
  int retval;
  retval = my_main ();
  _exit(retval);
}

int my_main(void)
{
  printf("Hello\n");
  return 0;
}

Скомпилируйте код с помощью:

gcc -o no_main no_main.c -nostartfiles

-nostartfiles не будет включать файл запуска по умолчанию. Вы указываете на основной файл ввода с помощью _start.

main - это не что иное, как предопределенная точка входа для кода пользователя. Поэтому вы можете назвать его как угодно, но в конце дня вам нужна точка входа. В C / C ++ и других языках имя выбирается как main, если вы создаете другой язык или взламываете источники этих языковых компиляторов, тогда вы можете изменить имя main на pain, но это принесет боль, так как это будет нарушать стандарты.

Но манипулирование именем функции входа полезно для кода ядра, первой функции, запускаемой в ядре, или кода, написанного для встроенных систем.

8 голосов
/ 13 августа 2011

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

5 голосов
/ 13 августа 2011

Да, это возможно для компиляции без main, но вы не можете пройти этап связывания.

5 голосов
/ 15 августа 2011

Да

$ cat > hwa.S
write = 0x04
exit  = 0xfc
.text
_start:
        movl    $1, %ebx
        lea     str, %ecx
        movl    $len, %edx
        movl    $write, %eax
        int     $0x80
        xorl    %ebx, %ebx
        movl    $exit, %eax
        int     $0x80
.data
str:    .ascii "Hello, world!\n"
len = . -str
.globl  _start
$ as -o hwa.o hwa.S
$ ld hwa.o
$ ./a.out
Hello, world!

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

Причинавам нужен основной, потому что обычно ваша «основная программа» на самом деле просто еще один модуль.Точка входа находится в предоставленном библиотекой стартовом коде, написанном в некоторой комбинации C и ассемблера, и этот библиотечный код просто вызывает main, поэтому обычно вам нужно предоставить его.Но запустите компоновщик напрямую, и вы не сделаете этого.

Включить модуль C 1 ...

Mac:~/so$ cat > nomain.S
.text
.globl start
start:
        call   _notmain
Mac:~/so$ as -o nomain.o nomain.S
Mac:~/so$ cat > notmain.c
#include <unistd.h>

void notmain(void) {
  write(1, "hi\n", 3);
  _exit(0);
}
Mac:~/so$ cc -c notmain.c
Mac:~/so$ ld -w nomain.o notmain.o -lc
Mac:~/so$ ./a.out
hi


1.И я также здесь переключаюсь на x86-64.
3 голосов
/ 13 августа 2011

«Без использования main» также может означать, что в main не допускается логика, но сам main существует.Я могу себе представить, что этот вопрос прояснился, но поскольку он здесь не прояснен, это еще один возможный ответ:

struct MainSub
{
   MainSub()
   {
      // do some stuff
   }
};

MainSub mainSub;

int main(int argc, char *argv[]) { return 0; }

Что здесь произойдет, так это то, что материал в конструкторе MainSub будет выполняться раньшенеиспользуемый main выполняется, и вы можете разместить там логику программы.Это, конечно, требует C ++, а не C (также не ясно из вопроса).

2 голосов
/ 26 июля 2016

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

#import <iostream>

class NoMain
{
public:
    NoMain()
    {
        std::cout << "Hello World!" << std::endl;
        exit(0);
    }
} mainClass;

Я дал имя файла как noname.cpp, а опция компиляции:

g++ nomain.cpp -Wl,-e,_mainClass -v

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

2 голосов
/ 13 августа 2011

Я думаю, что ссылка на макрос была для переименования основной функции, ниже не мой код, и демонстрирует это. Хотя компилятор все еще видит главную функцию, но технически нет главной с исходной точки зрения. Я получил это здесь http://www.exforsys.com/forum/c-and-c/96849-without-main-function-how-post412181.html#post412181

#include<stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)

int begin()
{
  printf(" hello ");
}
...