日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言程序可以没有main函数

發(fā)布時間:2025/6/15 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言程序可以没有main函数 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文鏈接:http://www.wufangbo.com/175871/

學(xué)習(xí)C語言的同學(xué)都知道,每個C程序要有一個main函數(shù),程序從main函數(shù)開始執(zhí)行,在main函數(shù)中結(jié)束。但事實(shí)上,C程序也可以沒有main函數(shù),或者說自己可以指定入口函數(shù)。下面這篇文章介紹了如何實(shí)現(xiàn)這一過程。這篇文章轉(zhuǎn)自:http://www.codeweblog.com,作者不詳。學(xué)習(xí)這個內(nèi)容對程序設(shè)計沒啥影響,但能更深入地了解程序編譯和鏈接的原理。

? ? 這篇文章主要介紹了c語言之沒有main函數(shù)的helloworld示例,本文分解了帶main函數(shù)的helloworld示例,從而分析出不需要main函數(shù)的helloworld示例,需要的朋友可以參考下。

? ? 幾乎所有程序員的第一堂課都是學(xué)習(xí)helloworld程序,下面我們先來重溫一下經(jīng)典的C語言helloworld。

/* hello.c */?

#include <stdio.h>?

int main()?

{?

??? printf("helloworld!/n");?

??? return 0;?

}?

? ? 這是一個簡單的不能再簡單的程序,但它包含有一個程序最重要的部分,那就是我們在幾乎所有代碼中都能看到的main函數(shù),我們編譯成可執(zhí)行文件并查看符號表,過濾出里面的函數(shù)如下(為了方便查看我手動調(diào)整了grep的輸出的格式,所以和你的輸出格式是不一樣的)

$ gcc hello.c -o hello?

$ readelf -s hello | grep FUNC

Num: ? ? Value ? ? ? ? ? Size ? ?Type??? Bind ? ? Vis ? ? ? ? NdxName?

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 aliyunzixun@xxx.com@GLIBC_2.2.5?

52: 00000000004005b8 ? ? ?0 ? ? ?FUNC??? GLOBAL ?DEFAULT ? ? ?14 _fini?

53: 0000000000000000 ? ? ?0 ? ? ?FUNC??? GLOBAL ?DEFAULT ? ? ?UND aliyunzixun@xxx.com@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函數(shù)開始執(zhí)行的,雖然我們只寫了一個main函數(shù),但從上面的函數(shù)表可以看到還有其它很多函數(shù),比如_start函數(shù)。實(shí)際上程序真正的入口并不是main函數(shù),我們以下面命令對hello.c代碼進(jìn)行編譯:

$ gcc hello.c -nostdlib?

/usr/bin/ld: warning: cannot find entrysymbol _start; defaulting to 0000000000400144

? ? -nostdlib命令是指不鏈接標(biāo)準(zhǔn)庫,報錯說找不到entry symbol _start,這里是說找不到入口符號_start,也就是說程序的真正入口是_start函數(shù)。

? ? 實(shí)際上main函數(shù)只是用戶代碼的入口,它會由系統(tǒng)庫去調(diào)用,在main函數(shù)之前,系統(tǒng)庫會做一些初始化工作,比如分配全局變量的內(nèi)存,初始化堆、線程等,當(dāng)main函數(shù)執(zhí)行完后,會通過exit()函數(shù)做一些清理工作,用戶可以自己實(shí)現(xiàn)_start函數(shù):

/* hello_start.c */?

#include <stdio.h>?

#include <stdlib.h>?

_start(void)?

{?

??? printf("hello world!/n");?

??? exit(0);?

}?

? ? 執(zhí)行如下編譯命令并運(yùn)行:

$ gcc hello_start.c -nostartfiles -ohello_start?

$ ./hello_start?

hello world!

? ? 這里的-nostartfiles的功能是Do notuse the standard system startup files when linking,也就是不使用標(biāo)準(zhǔn)的startupfiles,但是還是會鏈接系統(tǒng)庫,所以程序還是可以執(zhí)行的。同樣我們查看符號表:

$ readelf -s hello_start | grep FUNC?

Num: ? ? ?Value ? ? ? ? ? Size ? ?Type ? ? Bind ? ? Vis ? ? ? ? ?NdxName?

20: ?0000000000400350 ? ? ?24 ? ? FUNC??? GLOBAL ? DEFAULT ? ? ? 10 _start?

21: ?0000000000000000 ? ? ?0 ? ? ?FUNC??? GLOBAL ? DEFAULT ? ? ? UND aliyunzixun@xxx.com@GLIBC_2.2.5?

22: ?0000000000000000 ? ? ?0 ? ? ?FUNC??? GLOBAL ? DEFAULT ? ? ? UND aliyunzixun@xxx.com@GLIBC_2.2.5

? ? 現(xiàn)在就只剩下三個函數(shù)了,并且都是我們自己實(shí)現(xiàn)的,其中printf由于只有一個參數(shù)會被編譯器優(yōu)化為puts函數(shù),在編譯時加-fno-builtin選項可以關(guān)掉優(yōu)化。

? ? 如果我們在_start函數(shù)中去掉exit(0)語句,程序執(zhí)行會出core,這是因為_start函數(shù)執(zhí)行完程序就結(jié)束了,而我們自己實(shí)現(xiàn)的_start里面沒有調(diào)用exit()去清理內(nèi)存。

? ? 好不容易去掉了main函數(shù),這時又發(fā)現(xiàn)必須得有一個_start函數(shù),是不是讓人很煩,其實(shí)_start函數(shù)只是一個默認(rèn)入口,我們是可以指定入口的

/* hello_nomain.c */?

#include <stdio.h>?

#include <stdlib.h>?

int nomain()?

{?

??? printf("helloworld!/n");?

??? exit(0);?

}

采用如下命令編譯?

$ gcc hello_nomain.c -nostartfiles -enomain -o hello_nomain?

? ? 其中-e選項可以指定程序入口符號,查看符號表如下:

$ readelf -s hello_nomain | grep FUNC?

Num: ? ? Value ? ? ? ? ? ?Size ? ?Type ? ? ?Bind ? ? ? Vis ? ? ? NdxName?

20: ? 0000000000000000???? 0 ? ? ?FUNC??? ?GLOBAL ? ?DEFAULT ? ? aliyunzixun@xxx.com@GLIBC_2.2.5?

21: ? 0000000000000000???? 0 ? ? ?FUNC??? ?GLOBAL ? ?DEFAULT ? ? aliyunzixun@xxx.com@GLIBC_2.2.5?

22: ? 0000000000400350 ? ? 24 ? ? FUNC ? ? GLOBAL ? ?DEFAULT ? ? 10 nomain

?

? ? 對比hello_start的符號表發(fā)現(xiàn)只是將_start換成了nomain。

? ? 到這里我們就很清楚了,程序默認(rèn)的入口是標(biāo)準(zhǔn)庫里的_start函數(shù),它會做一些初始化工作,調(diào)用用戶的main函數(shù),最后再做一些清理工作,我們可以自己寫_start函數(shù)來覆蓋標(biāo)準(zhǔn)庫里的_start,甚至可以自己指定程序的入口。


總結(jié)

以上是生活随笔為你收集整理的C语言程序可以没有main函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。