首页 > 编程知识 正文

c语言void main()报错,c语言编程题

时间:2023-05-04 17:45:42 阅读:175768 作者:4250

还差一点,全程序猴子的第一节课就要学习hello世界的程序了。 先来看看经典的c语言hello世界吧

/* hello.c */

#包含

int main () )

{

打印(hello world!

();

返回0;

}

这是一个再简单不过的程序。 但是,程序中有最重要的部分。 那就是我们还差一点就能在所有代码中看到的main函数。 我们编译成可执行文件,看符号表,过滤里面的函数。 例如,如下所示。 为了方便起见,我手动调整了grep的输出格式,所以和你的输出格式不同。

$ gcc hello.c -o hello

$ readelf -s hello | grep FUNC

num : valuesizetypebindvisndxname

2:000000000040040 c0funclocaldefault 13 call _ gmon _ start

3:00000000400430 funclocaldefault 13 _ _ do _ global _ dtors _ aux

3:0000000000004004 a0funclocaldefault 13 frame _ dummy

4033600000000000400580 funclocaldefault 13 _ _ do _ global _ ctors _ aux

4:00000000004004 e 02 funcglobaldefault 13 _ _ libc _ CSU _ fini

4:000000000004003 E0 funcglobaldefault 13 _ start

5:00000000000000000 funcglobaldefaultundputs @ @ glibc _ 2.2.5

5:0000000000004005 b 80 funcglobaldefault 14 _ fini

5:000000000000000000 funcglobaldefaultund _ _ libc _ start _ main @ @ glibc _ @

5:00000000004004 f 0137 funcglobaldefault 13 _ _ libc _ CSU _ init

62336000000000004004 c 421 funcglobaldefault 13 main

6336000000000000400390 funcglobaldefault 11 _ init

众所周知,用户的代码是从main函数执行的。 我们只写了一个main函数,从上面的函数表中可以看出有很多函数,比如_start函数。 实际上,程序的真正入口不是main函数。 使用以下命令编译hello.c代码

$ gcc hello.c -nostdlib

/usr/bin/LD : warning : cannotfindentrysymbol _ start; defaulting to 0000000000400144

-nostdlib命令是指如果未链接到标准库,并且找不到entry symbol _start,则会报告错误。 在这里,意味着找不到入口符号_start。 也就是说,程序的真正入口是_start函数

实际上,main函数只是用户代码的入口,由系统库调用。 在main函数之前,系统库会执行初始化任务,例如分配全局变量的内存。 初始化堆、线程等,执行main函数,然后使用exit () )函数进行清理。 用户可以自己实现_start函数

/* hello_start.c */

#包含

#包含

_start(void )

{

打印(hello world!

();

退出(0;

}

例如,执行以下编译命令

$ gcc hello _ start.c-no start files-o hello _ start

$ ./hello_start

hello世界!

这里的-nostartfiles的功能是donotusethestandardsystemstartupfileswhenlinking,也就是不使用标准的startup files,但是因为还是链接了系统库,所以程序让我们看看同样的符号表

$ readelf -s hello_start | grep FUNC

num : valuesizetypebindvisndxname

2033600000000000040035024 funcglobaldefault 10 _ start

2:00000000000000000 funcglobaldefaultundputs @ @ glibc _ 2.2.5

2:00000000000000000 funcglobaldefaultundexit @ @ glibc _ 2.2.5

现在只剩下三个函数了。 然后我们自己实现了。 因为其中printf只有一个参数由编译器优化为puts函数。 可以通过在编译时添加-fno-builtin选项来关闭优化

假设从_start函数中删除了exit(0)语句。 程序运行时出现core。 这是因为_start函数执行程序后就结束了。 在我们自己实现的_start中,没有调用exit )来清理内存

不,easy去除了主函数。 此时,您发现需要_start函数。 非常麻烦吗? 其实_start函数只是默认的入口,我们可以指定入口

/* hello_nomain.c */

#包含

#包含

int nomain () )

{

打印(hello world!

();

退出(0;

}

例如,用以下命令编译

$ gcc hello _ no main.c-no start files-enom ain-o hello _ no main

中-e选项允许指定程序条目符号。 请看符号表,例如以下所示

$ readelf-shello _ no main|grep func

num : valuesizetypebindvisndxname

20336000000000000000000 funcglobaldefaultundputs @ @ glibc _ 2.2.5

2:00000000000000000 funcglobaldefaultundexit @ @ glibc _ 2.2.5

2:0000000000040035024 funcglobaldefault 10 no main

通过对照hello_start的符号表,我们发现它只是用nomain替换了_start

至此,您已经清楚了,程序的缺省条目是标准库的_start函数。 进行调用用户的main函数的初始化工作。 最后做一些清理工作,我们可以自己编写_start函数来覆盖标准库的_start。 甚至可以自己指定程序的入口

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。