国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

C語言不支持重載,多種main()如何實現(xiàn)的呢?

開發(fā) 后端
今天借助本文,來分析下C語言中main()的實現(xiàn),順便解答下群里的這個問題。

大家都知道,我是做上層應(yīng)用的,對底層不是很了解,更別說那幫人在討論內(nèi)核的時候,根本插不上話。更多的時候,還是默默記筆記,緊跟大佬們的步伐??。

于是,為了調(diào)研這個問題,也查了相關(guān)資料。今天借助本文,來分析下C語言中main()的實現(xiàn),順便解答下群里的這個問題。

定義

作為C/C++開發(fā)人員,都知道m(xù)ain()函數(shù)是一個可執(zhí)行程序的入口函數(shù),大都會像如下這樣寫:

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

但是,作為一個開發(fā)老油條,也僅僅知道是這樣做的,當(dāng)看到二哥提出這個問題的時候,第一反應(yīng)是重載,但是大家都知道C語言是不支持重載的,那么有沒有可能使用的是默認(rèn)參數(shù)呢?如下這種:

int main(int argc = 1, char **argv = NULL)

好了,為了驗證我的疑問,咱們著手開始進(jìn)行分析。

ps:在cppreference上對于main()的聲明有第三個參數(shù)即char *envp[],該參數(shù)是環(huán)境變量相關(guān),因為我們使用更多的是不涉及此參數(shù)的方式,所以該參數(shù)不在本文的討論范圍內(nèi)。

斷點(diǎn)調(diào)試

為了能夠更清晰的理解main()函數(shù)的執(zhí)行過程,寫了一個簡單的代碼,通過gdb查看堆棧信息,代碼如下:

int main() {
return 0;
}

編譯之后,我們通過gdb進(jìn)行調(diào)試,在main()函數(shù)處設(shè)置斷點(diǎn),然后看堆棧信息,如下:

(gdb) bt
#0 main () at main.c:2
(gdb)

從上述gdb信息,我們看出main()位于棧頂,顯然,我們的目的是分析main()的調(diào)用堆棧信息,而這種main()在棧頂?shù)姆绞斤@然不足以解答我的疑問。

于是,查閱了相關(guān)資料后,發(fā)現(xiàn)可以通過其它方式打印出更詳細(xì)的堆棧信息。

編譯命令如下:

gcc -gdwarf-5 main.c  -o main

然后gdb的相關(guān)命令(具體的命令可以網(wǎng)上查閱,此處不做過多分析):

gdb ./main -q
Reading symbols from /mtad/main...done.
(gdb) set backtrace past-entry
(gdb) set backtrace past-main
(gdb) show backtrace past-entry
Whether backtraces should continue past the entry point of a program is on.
(gdb) show backtrace past-main
Whether backtraces should continue past "main" is on.

然后在main()處設(shè)置斷點(diǎn),運(yùn)行,查看堆棧信息,如下:

(gdb) bt
#0 main () at main.c:2
#1 0x00007ffff7a2f555 in __libc_start_main () from /lib64/libc.so.6
#2 0x0000000000400429 in _start ()
(gdb)

通過如上堆棧信息,我們看到_start()-->__libc_start_main()-->main(),看來應(yīng)該在這倆函數(shù)中,開始分析~~

_start()

為了查看_start()的詳細(xì)信息,繼續(xù)在_start()函數(shù)處打上斷點(diǎn),然后分析查看:

(gdb) r
Starting program: xxx
Missing separate debuginfos, use: debuginfo-install glibc-2.17-317.el7.x86_64
Breakpoint 1, 0x0000000000400400 in _start ()
(gdb) s
Single stepping until exit from function _start,
which has no line number information.
0x00007ffff7a2f460 in __libc_start_main () from /lib64/libc.so.6

通過如上分析,沒有看到_start()函數(shù)的可執(zhí)行代碼,于是通過網(wǎng)上搜索,發(fā)現(xiàn)_start()是用匯編編寫,于是下載了glibc2.5源碼,在路徑處sysdeps/i386/elf/start.S

#include "bp-sym.h"
.text
.globl _start
.type _start,@function
_start:
/* Clear the frame pointer. The ABI suggests this be done, to mark
the outermost frame obviously. */
xorl %ebp, %ebp
/* Extract the arguments as encoded on the stack and set up
the arguments for `main': argc, argv. envp will be determined
later in __libc_start_main. */
popl %esi /* Pop the argument count. */
movl %esp, %ecx /* argv starts just at the current stack top.*/
/* Before pushing the arguments align the stack to a 16-byte
(SSE needs 16-byte alignment) boundary to avoid penalties from
misaligned accesses. Thanks to Edward Seidl <seidl@janed.com>
for pointing this out. */
andl $0xfffffff0, %esp
pushl %eax /* Push garbage because we allocate
28 more bytes. */
/* Provide the highest stack address to the user code (for stacks
which grow downwards). */
pushl %esp
pushl %edx /* Push address of the shared library
termination function. */
#ifdef SHARED
/* Load PIC register. */
call 1f
addl $_GLOBAL_OFFSET_TABLE_, %ebx
/* Push address of our own entry points to .fini and .init. */
leal __libc_csu_fini@GOTOFF(%ebx), %eax
pushl %eax
leal __libc_csu_init@GOTOFF(%ebx), %eax
pushl %eax
pushl %ecx /* Push second argument: argv. */
pushl %esi /* Push first argument: argc. */
pushl BP_SYM (main)@GOT(%ebx)
/* Call the user's main function, and exit with its value.
But let the libc call main. */
call BP_SYM (__libc_start_main)@PLT
#else
/* Push address of our own entry points to .fini and .init. */
pushl $__libc_csu_fini
pushl $__libc_csu_init
pushl %ecx /* Push second argument: argv. */
pushl %esi /* Push first argument: argc. */
pushl $BP_SYM (main)
/* Call the user's main function, and exit with its value.
But let the libc call main. */
call BP_SYM (__libc_start_main)
#endif
hlt /* Crash if somehow `exit' does return. */
#ifdef SHARED
1: movl (%esp), %ebx
ret
#endif
/* To fulfill the System V/i386 ABI we need this symbol. Yuck, it's so
meaningless since we don't support machines < 80386. */
.section .rodata
.globl _fp_hw
_fp_hw: .long 3
.size _fp_hw, 4
.type _fp_hw,@object
/* Define a symbol for the first piece of initialized data. */
.data
.globl __data_start
__data_start:
.long 0
.weak data_start
data_start = __data_start

上述實現(xiàn)也是比較簡單的:

xorl %ebp, %ebp:將ebp寄存器清零。

popl %esi、movl %esp, %ecx:裝載器把用戶的參數(shù)和環(huán)境變量壓棧,實際上按照壓棧的方法,棧頂?shù)脑鼐褪莂rgc,接著其下就是argv和環(huán)境變量的數(shù)組。這兩句相當(dāng)于int argc = pop from stack; char **argv = top of stack。

call BP_SYM (__libc_start_main):相當(dāng)于調(diào)用__libc_start_main,調(diào)用的時候傳入?yún)?shù),包括argc、argv。

上述邏輯功能,偽代碼實現(xiàn)如下:

void _start() {
%ebp = 0;
int argc = pop from stack
char ** argv = top of stack;
__libc_start_main(main, argc, argv, __libc_csu_init, __linc_csu_fini,
edx, top of stack);
}

__libc_start_main

在上一節(jié)中,我們了解到,_start()才是整個可執(zhí)行程序的入口函數(shù),在_start()函數(shù)中調(diào)用__libc_start_main()函數(shù),該函數(shù)聲明如下:

STATIC int
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
int argc, char *__unbounded *__unbounded ubp_av,
#ifdef LIBC_START_MAIN_AUXVEC_ARG
ElfW(auxv_t) *__unbounded auxvec,
#endif
__typeof (main) init,
void (*fini) (void),
void (*rtld_fini) (void), void *__unbounded stack_end)
{
#if __BOUNDED_POINTERS__
char **argv;
#else
# define argv ubp_av
#endif
/* Result of the 'main' function. */
int result;
__libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up;
...
...
if (init)
(*init) (argc, argv, __environ MAIN_AUXVEC_PARAM);
...
result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
exit (result);
}

可以看出,在該函數(shù)中,最終調(diào)用了main()函數(shù),并傳入了相關(guān)命令行。(result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);)

截止到此,我們了解了整個main()函數(shù)的調(diào)用過程,但是,仍然沒有回答二哥的問題,main()是如何實現(xiàn)有參和無參兩種方式的,其實說白了,在標(biāo)準(zhǔn)中,main()只有一種聲明方式,即有參方式。無論是否有命令行參數(shù),都調(diào)用該函數(shù)。如果有參數(shù),則通過壓棧出棧(對于x86 32位)或者寄存器(x86 64位)的方式獲取參數(shù),然后傳入main(),如果命令行為空,則對應(yīng)的字段為空(即沒有從棧上取得對應(yīng)的數(shù)據(jù))。

責(zé)任編輯:龐桂玉 來源: C語言與C++編程
相關(guān)推薦

2024-03-12 09:13:28

Go語言main

2021-11-08 11:02:01

Go函數(shù)重載

2011-12-09 20:28:50

2024-03-08 08:51:59

Gomain函數(shù)

2021-02-01 13:53:53

StringlongJava

2024-01-01 08:10:40

Go語言map

2024-01-05 08:45:35

Go語言map

2022-02-28 08:17:24

重載函數(shù)JS前端

2018-12-18 14:15:27

Windows 10語言版本錯誤

2020-07-02 10:30:52

iPhone蘋果北斗

2021-01-22 15:31:47

JavaSwitchString

2010-01-11 15:21:18

C++語言

2010-02-05 15:59:26

C++函數(shù)重載

2011-03-07 09:45:51

FileZilla

2010-06-24 17:42:08

服務(wù)不支持chkcon

2021-04-20 19:23:07

語法switch-casePython

2020-10-09 06:48:19

Pythonswitch語句

2020-07-22 08:01:41

Python開發(fā)運(yùn)算符

2021-10-27 07:15:36

Go 循環(huán)引用

2022-04-26 10:13:00

哈希索引MySQLInnoDB
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

久久香蕉频线观| 美女脱光内衣内裤视频久久影院| 国产精品1区2区3区在线观看| 色777狠狠综合秋免鲁丝| 国产女主播在线| 视频在线在亚洲| 欧美大码xxxx| heyzo在线播放| 日韩一区在线免费观看| 国内精品二区| 丝袜美腿一区二区三区动态图| 91精品国产综合久久福利| 国产中文字幕二区| 亚洲一区欧美二区| 亚洲精品在线观| 久久超级碰视频| 一区二区国产精品视频| 黄色影院在线播放| 综合av第一页| 亚洲一一在线| 亚洲国产美女| 九九热精品视频国产| 影院在线观看全集免费观看| 偷拍与自拍一区| 日本二区视频| 成人欧美一区二区三区在线播放| 久久亚洲a v| 成人黄色大片在线观看| 亚洲春色在线| 青青草精品视频| 久久香蕉视频网站| 国产在线精品一区二区夜色 | 国产福利91精品一区二区三区| 亚洲自拍小视频| 久久久国产精品| 国产精品免费电影| 日韩三级在线| 国产视色精品亚洲一区二区| 亚洲看片一区| 欧洲一区二区在线 | 91麻豆swag| 成人网18免费网站在线| 欧洲另类一二三四区| 亚洲www色| 国产精品久久久久免费a∨| 日韩一区二区免费看| 人妻少妇精品久久| 激情av一区二区| 日韩网站中文字幕| 91在线色戒在线| 久久综合九色综合欧美亚洲| 国产福利电影在线| 欧美另类第一页| 老鸭窝毛片一区二区三区| 亚洲 欧美 日韩系列| 亚洲国产高清自拍| 色999日韩| 国产羞羞视频| 亚洲欧美福利视频| 欧美国产91| 国产免费福利| 欧美风情在线观看| 粉嫩13p一区二区三区| 精产国品自在线www| 国产精品久久久久一区二区| 久久99精品国产.久久久久久| 四虎影视精品成人| 国产欧美日韩高清| 国产三级欧美三级| 国产成人福利av| 五十路熟女丰满大屁股| 精品无人区乱码1区2区3区在线 | 欧美乱熟臀69xxxxxx| 99热国内精品| 免费看的国产视频网站| 九九九热精品免费视频观看网站| 日韩成人一区二区| 最新黄网在线观看| 亚洲精品一区二区毛豆| 日韩国产精品视频| 91碰在线视频| 狼人天天伊人久久| 亚洲综合在线网站| 久久久久久久久久久91| 国产精品成人免费在线| 日韩欧美高清一区二区三区| 精品国产av无码一区二区三区| 美女主播精品视频一二三四| 影音先锋欧美精品| 五月天亚洲视频| 色婷婷久久久久swag精品| 国产婷婷视频在线| 欧美精品久久久久| 麻豆精品一区二区综合av| 日韩欧美视频网站| 国产91丝袜在线观看| 成人免费在线观看网站| 懂色av一区二区三区免费观看| 色琪琪原网站亚洲香蕉| 久久久亚洲国产| 欧美猛男gaygay网站| 精品成人影院| 色影视在线观看| 国产在线拍揄自揄视频不卡99| 亚洲成人午夜影院| 欧美亚洲自偷自偷| av在线不卡精品| 美丽的小蜜桃4春潮| 91久久久亚洲精品| 亚洲精品98久久久久久中文字幕| 久久久久久电影| 国产日韩欧美三级| 澳门成人av| 99热国产在线| 九色中文视频| 毛片在线视频观看| 国内精品国语自产拍在线观看| 日韩在线观看免费| 91精品久久久久久蜜臀| 亚洲一级片在线观看| 久久久三级国产网站| 精品一区二区免费看| 亚洲成人在线| 日韩精选在线| 亚洲一区二区av| 国产美女福利在线观看| 小香蕉视频在线| 992tv在线观看在线播放| 日日噜噜夜夜狠狠久久丁香五月| 91中文字幕一区| 国产欧美日韩精品专区| 欧美中文在线观看| 另类图片亚洲另类| 亚洲欧美激情视频| 亚洲激情免费观看| 亚洲精品成人免费| 亚洲а∨天堂久久精品喷水| 欧美日韩在线精品一区二区三区激情 | 国产精品免费看一区二区三区| 欧美福利视频在线观看| 亚洲片av在线| 日韩无一区二区| 欧美视频免费看| caoporn视频在线观看| 成人影院在线播放| www视频在线观看免费| 国产精品久久一区| 欧美黑人国产人伦爽爽爽| 国产69精品久久久久9999| 91a在线视频| 成人淫片在线看| 欧美日韩亚洲一区二区三区四区| 五月天久久综合网| 国产中文字幕乱人伦在线观看| 国产日产欧美视频| 色影视在线视频资源站| 黄色动漫在线观看| 美女福利一区二区三区| 老司机成人在线| 欧美日韩一区自拍| 国产成人精品免费看| 国产三区在线成人av| 色欧美片视频在线观看| 亚洲男人的天堂在线播放| 97在线精品视频| 国产精品9999久久久久仙踪林| 久久久久久久久一区二区| 999在线观看视频| 最全影音av资源中文字幕在线| 亚洲欧美成人影院| 精品国内亚洲2022精品成人| 国产深夜精品| 亚洲免费av高清| 亚洲开心激情网| av一区二区三区免费| 日韩在线综合网| av中文天堂在线| 国产精品视频首页| 天堂在线一区二区| 亚洲欧美偷拍卡通变态| 精品国产一区二区三区不卡| 97欧美精品一区二区三区| 国产一区一区三区| av电影在线播放高清免费观看| 国产伦精品一区二区三区免费优势| 三级精品在线观看| 欧美亚洲日本国产| 欧美第一淫aaasss性| 国产综合精品一区二区三区| 50路60路老熟妇啪啪| 中文字幕资源网在线观看免费| 一区二区亚洲| 色婷婷久久99综合精品jk白丝| 青青久久av北条麻妃海外网| 玩弄中年熟妇正在播放| 天然素人一区二区视频| 成人午夜电影久久影院| 在线观看日韩av| 日本精品一区在线观看| 99亚洲乱人伦aⅴ精品|