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

騎著程式碼去流浪發表於2018-05-14

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為

#include <stdio.h>

int main(void)
{
    printf("hello,world\n");
	return 0;
}

即符號#的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程式的指令。流程是將這些指令從主存複製到暫存器,再從暫存器複製到顯示裝置上,最終顯示到螢幕上,流程如下圖:




相關文章