C/C++程序編譯運行過程

2021-02-15 C語言編程開發

簡單來說,整個過程分為四個階段:預處理(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++編程的視頻教程,有興趣或者正在學習的小夥伴一定要去看一看哦!會對你有幫助的~

分享(源碼、項目實戰視頻、項目筆記,基礎入門教程)

歡迎轉行和學習編程的夥伴,利用更多的資料學習成長比自己琢磨更快哦!

免費學習書籍:


免費學習資料:


相關焦點

  • 編譯C語言程序,使用 gcc 指令,而C++程序則推薦使用 g++指令!
    除此之外,當下的 GCC 編譯器還支持編譯 Go、Objective-C,Objective-C ++,Fortran,Ada,D 和 BRIG(HSAIL)等程序,甚至於 GCC 6 以及之前的版本還支持編譯 Java 程序。但本教程主要講解如何使用 GCC 編譯器編譯運行 C 和 C++ 程序,因此有關其它程式語言如何使用 GCC 編譯器編譯,將不再做具體講解。
  • 簡要記錄丨VSCode 搭建基礎 C/C++ 編譯環境
    (Win10默認)和pwsh,文件名中有空格也可以編譯運行;注釋掉的適用於cmd(win7默認)、PS和bash,但文件名中有空格時無法運行15    "code-runner.saveFileBeforeRun": true, // run code前保存16    "code-runner.preserveFocus": true,     // 若為false,run code
  • 如何分析和提高(C/C++)程序的編譯速度?
    一個別人的vs 2010 的程序, 編譯, 加載數據, 運行, 需要個把小時。當改代碼然後再運行的時候,又要個把小時才能編譯看結果.這樣豈不是很浪費時間, 怎麼辦?這樣如何修改程序,怎麼提高效率啊?當我們遇到這樣情況的時候,是不是不知所措呢?怎麼防止遇到這樣的情況呢,我們來分析一下程序加速的一些方法。
  • C與C++混合編程
    首先,我先了解一下編譯的過程。分為四步:預處理(預處理用於將所有的#include頭文件以及宏定義替換成其真正的內容)——編譯(將經過預處理之後的程序轉換成特定彙編代碼(assembly code)的過程)——彙編(彙編過程將上一步的彙編代碼轉換成機器碼)——連結(連結過程將多個目標文以及所需的庫文件(.so等)連結成最終的可執行文件).
  • gcc&arm-linux-gcc編譯過程詳解
    第1節_gcc編譯器1_常用選項_編譯過程詳解gcc的使用方法gcc [選項] 文件名gcc常用選項 一個c/c++文件要經過預處理、編譯、彙編和連結才能變成可執行文件。 上面一連串命令有點多,gcc會對.c文件默認進行預處理操作,使用-c指明編譯、彙編,從而得到.o文件, 再將.o文件進行連結,得到可執行應用程式。簡化的命令如下:
  • Visual Studio 2017 編譯C程序教程出爐!
    中間框選擇c++文件,下面名稱位置原來是.cpp文件,這是編寫c++的,如果要編寫c程序的話要改成.c然後就可以點擊添加然後各位小夥伴就可以編寫C程序了!編寫完後可以右擊C程序文件編譯,然後可以選擇調試下拉菜單選擇執行,或者直接按Ctrl+F5直接執行。到了這裡相信各位看官都可以用Visual Studio 2017學習自己的c了再也不用閹割的VC++6.0啦。
  • C++中const與C中的const使用對比
    /a.outstartc=63、const修飾的全局變量在只讀存儲區分配空間4、const只在編譯期有用,在運行期無用。另外關於c語言裡面常用的const幾種用法,可以我之前寫的文章(小聲說提示一下,當時第一次寫文章,排版排的差勁,還請理解!)
  • 給宇宙最強Visual Studio Code配置編譯和運行C/C++
    來自:Linux迷  https://www.linuxmi.com/ubuntu-visual-studio-code-c.html
  • Linux上配置 Visual Studio Code 編譯和運行C/C++
    C++ 是一種靜態類型的、編譯式的、通用的、大小寫敏感的、不規則的程式語言,支持過程化編程、面向對象編程和泛型編程。當今許多作業系統,系統驅動程序,瀏覽器和遊戲都使用C++作為其核心語言,從而使其成為最受歡迎的語言之一。微軟的Visual Studio Code是一個功能強大的IDE(集成開發環境),為開發人員提供一流的特性,比如嵌入式Git控制、智能代碼完成、代碼重構、語法高亮顯示、調試支持和代碼段。
  • python+C、C++混合編程的應用
    python與C/C++混合編程的本質是python調用C/C++編譯的動態連結庫,關鍵就是把python中的數據類型轉換成c/c++中的數據類型,給編譯函數處理,然後返回參數再轉換成python中的數據類型。
  • 安卓模擬器安裝和第一個c++安卓程序編譯運行~1
    static {        //在運行期間,APP 的 MainActivity 會調用 System.loadLibrary() 方法,加載 native library        System.loadLibrary("native-lib");    }    @Override    protected void onCreate
  • GCC 程序編譯的靜態連結和動態連結
    如果可執行文件只是包含了文件名,讓載入器在運行時能夠尋找程序所需要的函數庫,稱之為動態連結。動態連結允許系統提供一個龐大的函數庫集合,可以提供許多有用的服務,程序在運行時尋找它們。動態連結使用動態連結庫進行連結,生成的程序在執行的時候需要加載所需的動態庫才能運行。動態連結生成的程序體積較小,但是必須依賴所需的動態庫,否則無法執行。
  • C/C++條件編譯
    \n"); #endif #if __linux__         printf("Linux作業系統\n"); #endif return 0;}在windows平臺運行上述程序,輸出:#ifdef命令用於宏定義的條件編譯,#ifdef可以認為是#ifdefined的縮寫。
  • Windows環境配置使用c,c++和fortran
    2. 啟動cmd。搜索框輸入cmd,選擇命令提示符。或者在Window系統下找到命令提示符。輸入gcc,g++,gfortran。如圖顯示:compilation terminated即為安裝成功(報錯是因為沒有給要編譯的輸入文件)。配置不成功會顯示類似,找不到gcc,g++,gfortran編譯器的信息。
  • Java內存管理-程序運行過程(一)
    到這裡如果你還沒有看懂Java是屬於哪一種的話,請繼續往下看,學過c++/java 這類程序語言的夥伴肯定知道,這些程序最終都是依賴作業系統來執行的。那麼,可以這樣理解,我們的程序就好像 」漢語「 ,而作業系統只懂英語,為了讓作業系統能夠聽過我們程序說的話(執行程序),可以選擇第二種,在執行程序之前先編譯成和作業系統相關的代碼(漢語->英語),比如C/C++ 將cpp文件編譯成exe文件,然後由作業系統執行,也就是編譯執行。
  • 一個神奇的腳本,一鍵運行各類程序(for Notepad++)
    』】前言一年前,我在公眾號裡寫過一篇文章 『windows下用Notepad++開發Python、C/C++』,大概講了如何用notepad++內置的運行命令來編譯運行相應程序,現在看來,略顯簡陋了如今,我將分享一個前陣子琢磨了一整天寫的 notepad++ 腳本給大家,可以一鍵編譯或運行Python/C/C++/Java 程序
  • Dev C++使用教程(使用Dev C++編寫C語言程序)
    Dev C++ 支持單個源文件的編譯,如果你的程序只有一個源文件(初學者基本都是在單個源文件下編寫代碼),那麼不用創建項目,直接運行就可以;如果有多個源文件,才需要創建項目。但是這並不影響使用,我們在填寫源文件名稱時把後綴改為.c即可,編譯器會根據源文件的後綴來判斷代碼的種類。上圖中,我們將源文件命名為hello.c。2) 生成可執行程序在上方菜單欄中選擇「運行 --> 編譯」,就可以完成 hello.c 源文件的編譯工作。
  • windows系統安裝gcc編譯器----c/c++語言編譯器
    2.這裡安裝的是c++編譯器,要按安裝別的看下面介紹 4.安裝c 和 c++ 編譯器 請按圖勾上然後去選擇 installation 菜單中的 apply changes 去安裝: 它是一個可自由使用和自由發布的Windows特定頭文件和使用GNU工具集導入庫的集合,允許你在GNU/Linux和Windows平臺生成本地的Windows程序而不需要第三方C運行時(C Runtime)庫。
  • 面試官:Linux下如何編譯C程序?
    下直接使用gcc來編譯,編譯過程是Linux嵌入式編程的基礎,也是嵌入式高頻基礎面試問題。一、命令行編譯及各個細分編譯過程hello.c示例代碼:#include <stdio.h>int main(void){  printf("Hello world\n"); return 0;}
  • 如何在 Ubuntu/Debian Linux 上編寫、編譯和運行一個 C 程序 | Linux 中國
    你是如何在 Linux 上使用 C 編寫你的程序的?它確實是非常簡單的,由三個簡單的步驟組成。步驟 1: 編寫你的 C 程序,並使用一個 .c 的擴展名進行保存。例如,my_program.c 。步驟 2: 在一個終端中使用 gcc 編譯器來編譯程序並生成目標文件,像這樣:gcc -o my_program my_program.c步驟 3: 在 Linux 中,你可以以運行生成的對象文件的方式來運行你的 C 程序:這只是如何在 Linux 中編譯和運行 C 程序的簡要總結。