是否可以在不使用main()函数的情况下编写程序?

Exp*_*ice 33 c c++ program-entry-point compilation

我在采访中不断提出这个问题:

不使用main()函数编写程序?

我的一个朋友向我展示了一些使用宏的代码,但我无法理解它.

所以问题是:

是不是真的可以编写和编译程序main()

Alo*_*ave 27

不,你不能,除非你在freestanding environment(嵌入式环境OS内核等)编写程序,其中起点不必main().根据C++标准main()是任何程序的起点hosted environment.

按照:

C++ 03标准3.6.1主要功能

1程序应包含一个名为main的全局函数,它是程序的指定开始.实现定义是否需要独立环境中的程序来定义主函数.[注意:在独立环境中,启动和终止是实现定义的; startup包含具有静态存储持续时间的命名空间作用域对象的构造函数的执行; 终止包含具有静态存储持续时间的对象的析构函数的执行.


什么是freestanding Environment什么Hosted Environment
C++标准中定义了两种符合实现的方法; hostedfreestanding.

一个freestanding实现是一个专为那些没有操作系统的好处执行的程序.
对于Ex:OS内核或嵌入式环境将是一个独立的环境.

使用操作系统设施的程序通常在a 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>
Run Code Online (Sandbox Code Playgroud)


Che*_*Alf 17

在标准C++ main中,需要一个函数,因此这个问题对标准C++没有意义.

在标准C++之外,您可以编写Windows特定程序并使用Microsoft的自定义启动函数(wMain,winMain,wWinmain).在Windows中,您还可以将程序编写为DLL并使用rundll32来运行它.

除此之外,您可以创建自己的小型运行时库.曾经是一项普通的运动.

最后,根据标准的ODR规则,您可以获得聪明和反驳,main不会"使用",因此任何程序都有资格.呸! 虽然除非面试官有不同寻常的幽默感(他们不会问他们是否有问题),但他们认为这不是一个好的答案.

  • 我不是匿名的downvoter - 但我怀疑它的投票反对这是不可接受的答案,当它不准确时.这是一个非常糟糕的面试问题 - 但这个答案具有误导性,因为它只适用于(公认的更常见的)托管环境. (3认同)

mik*_*iku 15

没有可见主函数的示例程序.

/* 
    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");
}
Run Code Online (Sandbox Code Playgroud)

来自:http://learnhacking.in/c-program-without-main-function/

  • 这段代码不是没有主要的.`gcc -E file.c`会给你实际编译的代码. (7认同)
  • 实际上,[这个](http://www.ideone.com/m1sOZ)和`#define begin()main()`一样好,你可以添加很多鲜为人知的/流行的C/C++构造和掩码但是必须为托管环境实现定义主要内容,在此处添加此注释,因为如果没有这个,答案可能会对新手产生误导. (5认同)

pho*_*xis 11

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;
}
Run Code Online (Sandbox Code Playgroud)

用以下代码编译代码:

gcc -o no_main no_main.c -nostartfiles
Run Code Online (Sandbox Code Playgroud)

-nostartfiles不包括默认的启动文件.您指向主条目文件_start.

main只不过是用户代码的预定义入口点.因此,您可以为其命名,但在一天结束时,您确实需要一个入口点.在C/C++和其他语言的名称被选为main如果你把另一种语言或破解这些语言编译器的源代码,那么你可以更改名称mainpain,但它会带来痛苦,因为这将违反标准.

但是,操作入口函数名称对于内核代码,在内核中运行的第一个函数或为嵌入式系统编写的代码非常有用.


Joh*_*itb 8

他们可能会参考为独立实施而编写的程序.C++标准定义了两种实现.一个是托管实现.为这些实现编写的程序需要具有一个main功能.但是,main如果独立实现不需要,则不需要任何功能.这对于不在操作系统下运行的操作系统内核或嵌入式系统程序很有用.


Mah*_*esh 5

是的,可以用main编译,但你不能通过链接阶段.

 g++ -c noMain.cpp -o noMain.o
Run Code Online (Sandbox Code Playgroud)


Dig*_*oss 5

$ 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!
Run Code Online (Sandbox Code Playgroud)

真正运行可执行文件的内核对内部符号一无所知,它只是传输到可执行映像头中以二进制文件指定的入口点.

你需要一个主要的原因是因为通常你的"主程序"实际上只是另一个模块.入口点在库提供的启动代码中,以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
Run Code Online (Sandbox Code Playgroud)


我也在这里切换到x86-64.