c語言程序的執行過程(以輸出hello,world爲例)

1.c源文件的存儲

任何數據在計算機中都以二進制的樣式進行存儲,即0和1兩種存儲表示,那麼c源文件中的各種字符要想存儲在計算機中作爲可執行的指令,那麼必須得以二進制0或1的形式存儲在其中,因此,需要將c源文件的需要被以某種方式“翻譯”成二進制存儲進計算機。

數據類型表示數字的類型如int,double 等類型在內存中是以換算的二進制存的,而字符類型等在內存中是以ASCII存的,這個通過查ASCII得到相應的二進制,然後存放於內存。
比如:32767 當作int型 爲整數,利用除2取餘法得到相應的二進制數存於內存(本來應該存補碼,但是正數的補碼和原碼相同)所佔的內存空間跟其對應的數據類型有關,可能還與機器有關,
而32767 當作字符  即“32767”,這時應該分解‘3’,‘2’,‘7’,‘6’,‘7’,然後查對應的ASCII碼 對應的值爲:0011001 00110010 00110111 00110110 00110111  所以在存放的即爲該二進制的組合,且佔5個字節的內存
將指定的字符“翻譯”成對應二進制文件需要“統一”的“密碼本”,使得在任何一臺計算上c源文件都以相同的二進制形式存儲。而翻譯這個c源文件的“密碼本”就是ASCII碼。

ASCII使用8位二進制數表示256個字符,這些字符包括32個大小寫字符,10個數字,以及其他的字符,例如,一個輸出“hello,world”的ASCII爲

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. printf("hello,world\n");
  5. return 0;
  6. }

即符號#的ASCII碼爲35,i的ASCII爲105......

而ASCII中35的二進制爲0010 0011,i爲0110 1001......

因此c源文件在計算機中存儲爲0010 0011 0110 1001 ......

2.c源文件的編譯

Linux系統上的編譯hello.c:


c源文件僅僅是以二進制的形式存儲在計算機中,而我們要實現的是計算機輸出“hello,world”,那麼需要將這些二進制文件編譯成計算機可以識別的指令,“告訴”計算機我們要輸出“hello world”。

構成這些計算機可以識別的二進制指令稱爲機器語言,因此,c語言的編譯就是編譯成機器語言共計算機執行。

在Linux系統中,將c源文件編譯成可執行的二進制指令文件是由gcc編譯器完成的,gcc是gnu組織的開發的編程語言編譯器。

輸出“hello,world”的hello.c的編譯流程:


編譯一個hello.c的程序總共分爲四個階段:預處理,編譯,彙編和鏈接

預處理階段:預處理階段是根據程序中字符#開頭的命令並執行相關操作,在holle.c中#開頭的第一行爲#include <stdio.h>,預處理器就讀取c庫中的stdio.h的內容將其插入到hello.c文本中生成一個新的文件hello.i;

編譯階段:編譯器ccl將hello.i翻譯彙編程序儲存在文件hello.s中,其中的main作爲一個函數給出了機器語言的輸出指令;

	.file	"hello.c"
	.section	.rodata
.LC0:
	.string	"hello,world"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$.LC0, %edi
	movl	$0, %eax
	call	printf
	movl	$0, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609"
	.section	.note.GNU-stack,"",@progbits

彙編階段:彙編器將hello.s中的彙編語言翻譯成計算機可以識別的機器語言存爲hello.o二進制文件;

鏈接階段:在c源文件中我們引用了printf打印函數,而計算機要識別這個函數也要由二進制指令組成。而在頭部文件中stdio.h作爲c語言的標準庫,其中已經定義了printf的接口,系統根據接口去讀取已經寫好的printf.o二進制指令文件,將其與hello.o文件合併爲hello二進制文件,稱爲可執行目標文件或可執行文件。

3.hello文件的執行過程

Linux上執行hello打印輸出:


打開shell從鍵盤輸入./hello,shell會優先把輸入的字符串當做內置命令,若不是則會將其當做可執行文件的名字處理。shell將計算機I/o接口連接的輸入設備輸入的字符串通過總線接口存入寄存器,再存入內存中。

從鍵盤中讀取shell命令流程:


完成./hello輸入後,當從鍵盤上輸入回車後,shell得知命令輸入完成,開始執行一系列指令從磁盤複製hell文件到內存中,流程如下:


當hello文件被複制到主存之後,處理器開始執行hello程序的main程序的指令。流程是將這些指令從主存複製到寄存器,再從寄存器複製到顯示設備上,最終顯示到屏幕上,流程如下圖:




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章