没有main函数的helloworld
/* hello.c */
#include <stdio.h> int main()
{
printf("hello world!\n");
return 0;
}
这是一个简单得不能再单的程序。但它包括有一个程序最重要的部分。那就是我们在差点儿全部代码中都能看到的main函数。我们编译成可运行文件并查看符号表,过滤出里面的函数例如以下(为了方便查看我手动调整了grep的输出的格式,所以和你的输出格式是不一样的)
$ gcc hello.c -o hello
$ readelf -s hello | grep FUNC
Num: Value Size Type Bind Vis Ndx Name
27: 000000000040040c 0 FUNC LOCAL DEFAULT 13 call_gmon_start
32: 0000000000400430 0 FUNC LOCAL DEFAULT 13 __do_global_dtors_aux
35: 00000000004004a0 0 FUNC LOCAL DEFAULT 13 frame_dummy
40: 0000000000400580 0 FUNC LOCAL DEFAULT 13 __do_global_ctors_aux
47: 00000000004004e0 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
48: 00000000004003e0 0 FUNC GLOBAL DEFAULT 13 _start
51: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.2.5
52: 00000000004005b8 0 FUNC GLOBAL DEFAULT 14 _fini
53: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
58: 00000000004004f0 137 FUNC GLOBAL DEFAULT 13 __libc_csu_init
62: 00000000004004c4 21 FUNC GLOBAL DEFAULT 13 main
63: 0000000000400390 0 FUNC GLOBAL DEFAULT 11 _init
大家都知道用户的代码是从main函数開始运行的。尽管我们仅仅写了一个main函数,但从上面的函数表能够看到还有其他非常多函数,比方_start函数。实际上程序真正的入口并非main函数,我们以以下命令对hello.c代码进行编译
$ gcc hello.c -nostdlib
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400144
-nostdlib命令是指不链接标准库,报错说找不到entry symbol _start,这里是说找不到入口符号_start,也就是说程序的真正入口是_start函数
实际上main函数仅仅是用户代码的入口,它会由系统库去调用,在main函数之前,系统库会做一些初始化工作,比方分配全局变量的内存。初始化堆、线程等,当main函数运行完后,会通过exit()函数做一些清理工作。用户能够自己实现_start函数
/* hello_start.c */
#include <stdio.h>
#include <stdlib.h> _start(void)
{
printf("hello world!\n");
exit(0);
}
执行例如以下编译命令并执行
$ gcc hello_start.c -nostartfiles -o hello_start
$ ./hello_start
hello world!
这里的-nostartfiles的功能是Do not use the standard system startup files when linking,也就是不使用标准的startup files,可是还是会链接系统库,所以程序还是能够运行的。相同我们查看符号表
$ readelf -s hello_start | grep FUNC
Num: Value Size Type Bind Vis Ndx Name
20: 0000000000400350 24 FUNC GLOBAL DEFAULT 10 _start
21: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.2.5
22: 0000000000000000 0 FUNC GLOBAL DEFAULT UND exit@@GLIBC_2.2.5
如今就仅仅剩下三个函数了。而且都是我们自己实现的。当中printf因为仅仅有一个參数会被编译器优化为puts函数。在编译时加-fno-builtin选项能够关掉优化
假设我们在_start函数中去掉exit(0)语句。程序运行会出core。这是由于_start函数运行完程序就结束了。而我们自己实现的_start里面没有调用exit()去清理内存
好不easy去掉了main函数。这时又发现必须得有一个_start函数,是不是让人非常烦,事实上_start函数仅仅是一个默认入口,我们是能够指定入口的
/* hello_nomain.c */
#include <stdio.h>
#include <stdlib.h> int nomain()
{
printf("hello world!\n");
exit(0);
}
採用例如以下命令编译
$ gcc hello_nomain.c -nostartfiles -e nomain -o hello_nomain
当中-e选项能够指定程序入口符号,查看符号表例如以下
$ readelf -s hello_nomain | grep FUNC
Num: Value Size Type Bind Vis Ndx Name
20: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.2.5
21: 0000000000000000 0 FUNC GLOBAL DEFAULT UND exit@@GLIBC_2.2.5
22: 0000000000400350 24 FUNC GLOBAL DEFAULT 10 nomain
对照hello_start的符号表发现仅仅是将_start换成了nomain
到这里我们就非常清楚了,程序默认的入口是标准库里的_start函数。它会做一些初始化工作,调用用户的main函数。最后再做一些清理工作,我们能够自己写_start函数来覆盖标准库里的_start。甚至能够自己指定程序的入口
没有main函数的helloworld的更多相关文章
- main函数中System.exit()的作用
main()主函数再熟悉不过,了解java的人也都知道System.exit()方法是停止虚拟机运行.那这里为什么还要单独写一篇博客,都是源于朋友发的一张最近刚买的T恤照片,就是上面这张图.这是一个经 ...
- linux编程之main()函数启动过程【转】
转自:http://blog.csdn.net/gary_ygl/article/details/8506007 1 最简单的程序 1)编辑helloworld程序,$vim helloworld. ...
- 大数据学习之Scala中main函数的分析以及基本规则(2)
一.main函数的分析 首先来看我们在上一节最后看到的这个程序,我们先来简单的分析一下.有助于后面的学习 object HelloScala { def main(args: Array[String ...
- Knowledge Point 20180303 详解main函数
学习Java的朋友想来都是从HelloWorld学起的,那么想来都对main函数不陌生了,但是main函数究竟是怎么回事呢?main函数中的参数是做什么的呢?main函数为什么能作为程序的入口呢?可不 ...
- VS2010-如何建立并运行多个含有main函数的文件
一.先说两个概念,解决方案与工程 在VS2010中,工程都是在解决方案管理之下的.一个解决方案可以管理多个工程,可以把解决方案理解为多个有关系或者没有关系的工程的集合. 每个应用程序都作为一个工程来处 ...
- [C#] 了解过入口函数 Main() 吗?带你用批处理玩转 Main 函数
了解过入口函数 Main() 吗?带你用批处理玩转 Main 函数 目录 简介 特点 方法的参数 方法的返回值 与批处理交互的一个示例 简介 我们知道,新建一个控制台应用程序的时候,IDE 会同时创建 ...
- 选择目录,选择文件夹的COM组件问题。在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常。
异常: 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式.请确保您的 Main 函数带有 STAThreadAttribute 标记. 只有将调试器附加到该进程才会引发此异常. ...
- eclipse的maven项目,如何使用java run main函数
项目使用maven管理,一般说来就使用jetty:run了.但是对于做功能测试和集成测试的用例,需要使用自定义的quickrun来运行进行测试环境的参数设定和功能隔离,google一番发现maven有 ...
- [汇编与C语言关系]2. main函数与启动例程
为什么汇编程序的入口是_start,而C程序的入口是main函数呢?以下就来解释这个问题 在<x86汇编程序基础(AT&T语法)>一文中我们汇编和链接的步骤是: $ as hell ...
随机推荐
- 【洛谷】2607: [ZJOI2008]骑士【树形DP】【基环树】
P2607 [ZJOI2008]骑士 题目描述 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬. 最近发生了一件可怕的事情,邪恶的Y国发动了一 ...
- 【对比分析三】CSS中 link 和@import 的区别
1). link 是 XHTML 标签,无兼容问题: @import 是在 CSS2.1 提出的,只有IE5以上才能识别. 2). 语法结构不同. link (链接式)只能放入HTML源码中,语法 ...
- 匹配<a href="url">content</a>
grep -Po '<a href="(.*.rmvb")>(.*)</a>' te.txt | sed -n 's/<a href=\(.*\)&g ...
- ParseFloat有超长的小数位数的解决
描述一下sum=parseFloat(num1)+parseFloat(num2),这个个sum=113.32000000000002,最后用了个Math.round(sum* 100)/100,解决 ...
- SQL Server 中添加表注释
今天在创建完表之后,发现没有办法给表添加注释说明,字段的注释可以在建表的时候就添加,上网查了一下使用SQL给表添加注释的方法,方法如下: -- 表加注释 EXEC sys.sp_addextended ...
- VS2010发布网站
- 用最简单的例子理解适配器模式(Adapter Pattern)
中国足球的水平虽然不高,但实际上,在每个城市会有一批足球爱好者,他们踢球.看球.懂球.有这样的2个足球爱好者,一个是左脚选手,另一个是右脚选手. public class PlayWithLeft { ...
- PhotoShop CS6 在2K屏幕下标题菜单等字体太小
对于此类问题,我更喜欢直接了当,不作解释,解决方法如下(大面积参考互联网内容): (1)Win+R按键打开运行对话框, 输入regedit,打开注册表. (2)展开HKEY_LOCAL_MACHINE ...
- spring mvc Controller中使用@Value无法获取属性值
在使用spring mvc时,实际上是两个spring容器: 1,dispatcher-servlet.xml 是一个,我们的controller就在这里,所以这个里面也需要注入属性文件 org.sp ...
- Android之Volley使用
转自:http://blog.csdn.net/lfdfhl/article/details/12223345 稍微做了一点儿修改 /** * 利用NetworkImageView显示网络图片 */ ...