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程序的指令。流程是將這些指令從主存複製到寄存器,再從寄存器複製到顯示設備上,最終顯示到屏幕上,流程如下圖: