代碼從編譯到運行經歷了什麼?你真的清楚嗎?

       在我們剛接觸C語言時,會發現老師教的都是安裝打開一個C語言的IDE,然後教如何創建工程、如何編譯代碼、如何運行代碼,但是老師並沒有講編譯的過程到底經歷了那些工作。
       C語言誕生於美國的貝爾實驗室,由D.M.Ritchie以B語言爲基礎發展而來,在它的主體設計完成後,Thompson和Ritchie用它完全重寫了UNIX,且隨着UNIX的發展,C語言也得到了不斷的完善。GCC的初衷是爲GNU操作系統專門編寫的一款編譯器。GNU系統是徹底的自由軟件。此處,“自由”的含義是它尊重用戶的自由 。
       GCC現已被大多數類Unix操作系統(如Linux、BSD、Mac OS X等)採納爲標準的編譯器。所以通過gcc這個編譯器來了解程序編譯經歷了,是很不錯的!

GNU工具

  • 編譯工具:把一個源程序編譯爲一個可執行程序
  • 調試工具:能對執行程序進行源碼或者彙編級調試
  • 軟件工程工具:用於協助多人開發或者大型軟件項目的管理。如make、CVS、Subvision
  • 其他工具:用於把多個文件鏈接成可執行文件的連接器,或者用作格式轉換的工具

GCC簡介

  • 全稱爲GUN CC,GUN項目中符合ANSI C標準編譯系統
  • 編譯如C、C++、Object C、JAVA、Fortran、Pascal、Modula-3和Ada等多種語言
  • GCC是可以在多種硬件平臺上編譯出可執行程序的超級編譯器,其執行效率與一般的編輯器相比平均效率高出20%~30%
  • 一個交叉平臺編譯器,適合在嵌入式平臺領域的開發編譯
  • gcc所支持後綴名解釋
後綴名 解釋程序類型
.c C原始程序
.C/.cc/.cxx C++原始程序
.m Objective-C原始程序
.i 已經過預處理的C原始程序
.ii 已經經過處理的C++原始程序
.s/.S 彙編語言原始程序
.h 預處理文件(頭文件)
.o 目標文件
.a/.so 編譯後的庫文件

編譯器的主要組件

  • 分析器:將源語言程序代碼轉換爲彙編語言(C到彙編),所以分析器需要知道目標機器的彙編語言。
  • 彙編器:彙編器將彙編語言代碼轉換爲CPU可以執行的字節碼
  • 鏈接器:將彙編器生成的單獨的目標文件組合成可執行的應用程序。連接器需要知道這種目標格式以便於工作。
  • 標準C庫:核心的C語言庫都有一個主要的C庫來提供,如果在應用程序中用到了C庫中的函數,這個庫就會通過鏈接器和源代碼連接來生成最終的可執行程序。

GCC的基本用法和選項

       GCC的最基本用法是:gcc [options] [filenames]

  • -c,只編譯,不連接成爲可執行文件,編譯器只是由輸入的.c等源代碼文件生成.o的後綴的目標文件,通常用於編譯不包含主程序的子程序文件。
  • -o output filename ,確定輸出文件名稱爲output filename,同時這個名稱不能和源文件同名。如果不給出這個選項,gcc就給出預設的可執行文件a.out
  • -g,產生符號調試工具(GUN的gdb)所必要的符號資訊,想要對源代碼進行調試,我們必須加入這個選項
  • -O,對程序進行優化編譯、連接,採用這個選項,整個源代碼會在編譯、連接過程中進行優化處理,這樣產生的可執行文件的執行效率可以提高,但是,編譯、連接的速度會相對慢一些。
  • -O2,比-O更好的優化編譯、連接,當然整個編譯、連接過程會很慢。
  • -I dirname,將dirname所指出的目錄加入到程序頭文件目錄列表中,是在預編譯過程中使用的參數
  • -L dirname,將dirname 所指出的目錄加入到程序函數檔案庫文件的目錄列表中,是在鏈接過程中使用的參數。

GCC的錯誤類型及對策

  • 第一類:C語法錯誤
           錯誤信息:文件source.c中第n行語法錯誤(systex error)。有些情況下,一個簡單的語法錯誤,gcc會出一大堆錯誤,我們要保持頭腦清醒,不要被嚇到!
  • 第二類:頭文件錯誤
           錯誤信息:找不到頭文件head.h(Can not find include file head.h)。這類錯誤是源代碼文件中的包含頭文件有問題,可能的原因有頭文件名錯誤、指定的頭文件所在目錄名錯誤等,也可能是錯誤的使用雙引號和尖括號。
  • 第三類:檔案庫錯誤
           錯誤信息:鏈接程序找不到所需的函數庫(ld:-lm:No such file or directory)。這類錯誤是與目標文件相連接的函數庫有錯誤,可能的原因是函數庫名錯誤、、指定的函數庫所在目錄名稱錯誤等,檢查的方法是使用find命令在可能的目錄中尋找相應的函數庫名,確定檔案庫及目錄的名稱並修改程序中及編譯選項中的名稱。
  • 第四類:未定義符號
           錯誤信息:有未定義的符號(Undefined symbo1)。這類錯誤是在連接過程中出現的,可能有兩種原因:一是使用者自己定義的函數或者全局變量所在源代碼文件,沒有被編譯連接,或者乾脆還沒有定義,這需要使用者根據實際情況修改源程序,給出全局變量或者函數的定義體;二是未定義的符號是一個標準的庫函數,在源程序中使用了該庫函數而連接過程中還沒有給定相應的函數庫的名稱,或者是該檔案庫的目錄名稱有問題,這時需要使用檔案庫維護命令ar檢查我們需要的庫函數到底位於哪–個函數庫中,確定之後,修改gcc連接選項中的-1和-L項。

GCC初體驗

       test.c文件內容如下:

#include<stdio.h>
int main()
{
	int i,j;
	j=0;
	i=j+1;
	printf("hello,world\n");
	printf("the result is %d\n",i);
}

編譯:$ gcc -o test test.c
執行:$ ./test
查看更詳細的的信息:$ gcc -v -o test test.c

GCC編譯過程

GCC的編譯流程分爲四個步驟:
       1、預處理(Pre-Processing)
       2、編譯(Compiling)
       3、彙編 (Assembliang)
       4、鏈接(Linking)
Alt
新建一個hello.c的文件,文件內容如下:

#include<stdio.h>
#include<math.h>

#define N 20
#define _DEBUG_

int main(int argc,const char*argc[])
{
	double m=615,n;
	m+=N;
	n=sqrt(m);
#ifdef _DEBUG_
	printf("debug:m=%lf n=%lf\n",m,n);
#else
	printf("debug:m=%lf n=%lf\n",m,n);
	return 0;
}

hello的演變過程:
Alt

  • 生成預處理代碼
$ gcc -E hello.c -o hello.i

通過命令:ls -l可以查看對比兩個文件
在這裏插入圖片描述
        可以發現hello.i比hello.c增加了不少內容,主要是放在系統提供的include文件中的。這裏需要注意的是預處理後生成的hello.i依舊是一個C程序,有語法錯誤也發現不了 !

  • 生成彙編代碼
        檢查語法錯誤,並生成彙編文件
$ gcc -S hello.c -o hello.s
  • 生成目標代碼
        方法一,用gcc直接從C源代碼中生成目標代碼:
$ gcc -c hello.s - o hello.o

            方法二,用匯編器從彙編代碼生成目標代碼:

$ as hello.s -o hello.o
  • 生成可執行程序
        將目標文件鏈接庫資源,生成可執行程序
$ gcc hello.s -o hello
./hello

調試器

  • 首先使用gcc對test.c進行編譯,注意一定要加上選項‘-g’
  • gcc -g hello.c -o hello
  • gdb hello

gdb是調試運行錯誤的,對於語法錯誤不能進行調試。

GDB調試流程

作用 參數
查看文件 (gdb)l
設置斷點 (gdb) b 6
查看斷點情況 (gdb)info b
運行代碼 (gdb)r
查看變量值 (gdb)p n
單步運行 (gdb)n/(gdb) s
恢復程序運行 (gdb)c
幫助 (gdb) help [command]

GDB調試

  • 運行被調試程序,設置所有的能影響該程序的參數和變量。
  • 保證被調試的程序在指定情況下停止運行。
  • 當被調用程序停止運行時,讓開發工程師檢查發生了什麼。
  • 根據每次調試器的提示信息來做響應的改變,以便修正某個錯誤引起的問題。

       不積小流無以成江河,不積跬步無以至千里。而我想要成爲萬里羊,就必須堅持學習來獲取更多知識,用知識來改變命運,用博客見證成長,用行動證明我在努力。
       如果我的博客對你有幫助、如果你喜歡我的博客內容,請“點贊” “評論” “收藏”一鍵三連哦!聽說點讚的人運氣不會太差,每一天都會元氣滿滿呦!如果實在要白嫖的話,那祝你開心每一天,歡迎常來我博客看看。

在這裏插入圖片描述

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