簡單來說,整個程序分為四個階段:預處理(Pre-Processing)、編譯(Compilation)、匯編(Assembling)、鏈接(Linking),

注意:其中源程式、修改了的源程式和匯編程式都是文本檔案,而可重定位目標程式和可執行目標程式都是二進制檔案,
似乎到這里就該結束了,因為整個程序已經講完了?,當然如果只是這樣介紹的話本文就沒有存在的價值了,我們還得再深入一點分別講解這四個階段?,
預處理
首先我們準備一個簡單的Hello World程式,命名為main.c,
#include<stdio.h>
#defineinfo "Hello, world\n"intmain(){// A simple program.printf(info);return0;}
預處理階段做的事情就是前處理器(cpp)根據以字符#開頭的代碼修改原始的C程式,
比如#include <stdio.h>,將頭檔案stdio.h中的內容加到程式文本中
比如#define info "Hello, world\n",會將宏定義的info替換成字串“Hello, world\n”(當然我這里只是為了舉例,一般我們不這么寫)
此外,會將注釋比如// A simple program.洗掉
預處理是直接對源檔案進行處理(不關注語法規則), 然后得到另一個C程式,通常以.i作為檔案擴展名,
我們可以在Linux系統(我這里用的是Ubuntu)下直接使用gcc -E main.c -o main.i命令得到預處理后的C程式main.i,我截取了一部分(總共有800+行),可以很明顯的看到:引入了頭檔案,info被替換了,注釋沒了,還添加了一些特殊的標記,告訴編譯器每行的來源,以便它可以使用它們來產生合理的錯誤訊息,
#1"main.c"#1"<built-in>"#1"<command-line>"#31"<command-line>"#1"/usr/include/stdc-predef.h"134............externvoidfunlockfile(FILE*__stream)__attribute__((__nothrow__,__leaf__));#868"/usr/include/stdio.h"34#2"main.c"2#3"main.c"intmain(){printf("Hello, world\n");return0;}
編譯
編譯階段做的事情就是編譯器(cc1)將C程式main.i翻譯成匯編語言程式main.s,
檢查C程式的語法錯誤
將檔案翻譯成中間代碼,即匯編語言
可選地優化翻譯后的中間代碼,獲得更好的性能
我們可以使用gcc -S main.i -o main.s得到翻譯后的匯編程式main.s,截取部分如下,
.file"main.c".text.LC0:.string"Hello, world".text.globl mainmain:.LFB0:.cfi_startproc pushq%rbp movq%rsp,%rbp.......LFE0:.size main,.-main.ident"GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0".section.note.GNU-stack,"",@progbits
其中的陳述句比如pushq %rbp描述了一條低級機器語言指令,匯編語言是有用的,它為不同高級語言的不同匯編器提供了通用的輸出語言,C匯編器和Fortran匯編器產生的輸出檔案都是一樣的匯編語言,
匯編
匯編階段做的事情就是匯編器(as)將main.s翻譯成機器語言指令,把這些指令打包成一種叫做可重定位目標程式的格式,并將結果保存在目標檔案main.o(Windows下為xx.obj而Linux下為xx.o)中,main.o是一個二進制檔案,如果我們使用文本編輯器打開main.o,會看到一堆亂碼,
我們可以使用gcc -c main.s -o main.o得到可重定位目標程式main.o,如下所示,
LF>?@@UH?=距ello,worldGCC:(Ubuntu7.3.0-27ubuntu1~18.04)7.3.0zRx#main.cmain_GLOBAL_OFFSET_TABLE_puts??? C ????.symtab.strtab.shstrtab.rela.text.data.bss.rodata.comment.note.GNU-stack.rela.eh_frame @0&90d+BWR@@
不出所料的一堆亂碼?,
鏈接
我們的main.c程式中使用了printf函式,printf函式是每個C編譯器都提供的標準C庫中的一個函式,它存在于一個名為printf.o的單獨預編譯好了的目標檔案中,
鏈接階段做的事情就是聯結器(ld)將需要用到的目標檔案比如main.o和printf.o進行合并,并生成一個可執行(目標)檔案,可以被加載到記憶體中,由系統執行,
實際上我們直接執行gcc main.c -o main命令得到的就是可執行檔案,Windows下為.exe,Linux下默認為具有可執行權限的a.out,當然我們使用了-o來自定義輸出檔案名,


以上就是整個編譯執行程序,
另外如果你想更好的提升你的編程能力,學好C語言C++編程!彎道超車,快人一步!筆者這里或許可以幫到你~
UP在主頁上傳了一些學習C/C++編程的視頻教程,有興趣或者正在學習的小伙伴一定要去看一看哦!會對你有幫助的~
分享(原始碼、專案實戰視頻、專案筆記,基礎入門教程)
歡迎轉行和學習編程的伙伴,利用更多的資料學習成長比自己琢磨更快哦!
免費學習書籍:

免費學習資料:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/255832.html
標籤:其他
