C語言 — 編譯和鏈接

目錄

  • 1.程序從源文件到結果輸出的執行過程
  • 2.預處理
  • 3.編譯
    • 3.1 詞法分析
    • 3.2 語法分析
    • 3.3 語義分析
    • 3.4 生成test.s文件
  • 4.匯編
  • 5.鏈接
  • 6.運行

1.程序從源文件到結果輸出的執行過程

在這里插入圖片描述

2.預處理

預處理階段的執行操作:

預處理階段會將#define定義的常量或宏進行替換,經過預處理后的文件#define的語句就不存在;

預處理階段會將注釋進行刪除,并對行號進行標識;

預處理階段會處理#include包含的頭文件,將其內容進行插入,此過程是可以遞歸進行的,因為包含的頭文件中可能包含其它頭文件;

預處理階段會處理#if #endif #elif #ifdef #else的條件編譯指令,對表達式進行判斷處理;

預處理階段會保留所有#pragma指令。

以下為簡單例子展示,創建三個文件:Add.h,Add.c,test.c

//Add.h文件
#pragma once//防止頭文件重復包含//類似效果
//#ifndef C //判斷是否沒有定義符號M
//
//#define C //定義符號C
//
//#include<stdio.h>//重復包含多次
//#include<stdio.h>
//#include<stdio.h>
//
//#endif//結束#ifenf條件判斷指令#include<stdio.h>#ifndef M //判斷是否沒有定義符號M#define M 100//定義符號M#endif//結束#ifenf條件判斷指令#define N 200int Add(int x, int y);//函數聲明
//Add.c文件
#include"Add.h"//包含頭文件
//函數定義
int Add(int x, int y)
{return (x + y);
}
//test.c文件
#include "Add.h"//包含頭文件int main()
{//輸出兩個數的和printf("%d", Add(M, N));return 0;
}

將以上代碼在VS環境下輸入后Ctrl + S保存,打開文件保存的位置,點擊輸入cmd后回車,打開cmd.

在這里插入圖片描述
在這里插入圖片描述
打開cmd后需要輸入指令,將源文件轉變為.i為后綴的中間文件

gcc -E test.c -o  test.i

在這里插入圖片描述
gcc是一個編譯器,需要下載相應的插件才可以使用,具體流程可以參考以下文章:

https://blog.csdn.net/qq_36318563/article/details/140336690

以上文章可能介紹的網站打不開,可以使用以下鏈接:MinGW下載

在這里插入圖片描述

輸入以上指令后會生成一個test.i的文件,可以在VS2022中打開觀察

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
因為頭文件的插入有400多行代碼,以上就不做過多的展示,最后可以看到處理后的#define定義的常量和條件編譯指令進行了處理和替換,并將注釋刪除。

3.編譯

編譯階段會進行詞法分析,語法分析和語義分析及優化,以下面例子為參考

  arr[n] = i + 1;

3.1 詞法分析

詞法分析階段會將語句的標識符,操作符,數字進行標記,以上語句可以得到以下標記

在這里插入圖片描述

3.2 語法分析

語法分析階段會根據標記生成語法樹,語法樹是根據表達式為節點的數。
在這里插入圖片描述

3.3 語義分析

語義分析階段是對語法層面的意思進行轉換,包括聲明,類型的匹配和轉換等,此時會報告錯誤信息,經過語義分析后的語法樹。

在這里插入圖片描述

3.4 生成test.s文件

對test.i的中間文件通過以下指令編譯生成test.s的文件

gcc -S test.i -o test.s

在這里插入圖片描述

在這里插入圖片描述
將生成的test.s文件在VS2022中打開,文件內容是匯編代碼。

	.file	"test.c".text.globl	_Add.def	_Add;	.scl	2;	.type	32;	.endef
_Add:
LFB10:.cfi_startprocpushl	%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl	%esp, %ebp.cfi_def_cfa_register 5movl	8(%ebp), %edxmovl	12(%ebp), %eaxaddl	%edx, %eaxpopl	%ebp.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endproc
LFE10:.def	___main;	.scl	2;	.type	32;	.endef.section .rdata,"dr"
LC0:.ascii "%d\0".text.globl	_main.def	_main;	.scl	2;	.type	32;	.endef
_main:
LFB11:.cfi_startprocpushl	%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl	%esp, %ebp.cfi_def_cfa_register 5andl	$-16, %espsubl	$16, %espcall	___mainmovl	$200, 4(%esp)movl	$100, (%esp)call	_Addmovl	%eax, 4(%esp)movl	$LC0, (%esp)call	_printfmovl	$0, %eaxleave.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endproc
LFE11:.ident	"GCC: (MinGW.org GCC-6.3.0-1) 6.3.0".def	_printf;	.scl	2;	.type	32;	.endef

4.匯編

匯編過程是將匯編代碼轉換為二進制代碼,每一條匯編語句都代表一條指令,將匯編語句與機器語句通過對照表轉換,不做任何優化,通過以下指令將test.s的文件轉換為test.o的目標文件。

gcc -c test.s -o test.o

在這里插入圖片描述

在這里插入圖片描述

打開test.o的文件,可以觀察到都是二進制的編碼

L?.textH? 0`.data@0?bss€0?rdataL@0@/4$P@0@/15Xt?@0@U夊婾婨衇肬夊冧饍?棖D$惹$d柩塂$?$韙擅悙%dGCC: (MinGW.org GCC-6.3.0-1) 6.3.0zR|?
A?B
I?<9A?B
u?6; @.file?gtest.c_Add _main.textF.data.bss.rdata#$X___main _printf ..rdata$zzz.eh_frame.rdata$zzz.eh_frame

5.鏈接

鏈接過程主要處理地址和空間分配,符號決議和符號重定位等操作,最后通過鏈接庫鏈接生成可執行程序。

例子:

add.c文件int n = 100;//全局變量int Add(int x,int y)
{return x + y;
}
test.c文件extern int n;//聲明外部符號
extern int Add(int ,int)//聲明外部符號int main()
{int r = Add(2,3)printf("r = %d",r);printf("n = %d",n);return 0;
}

地址和空間分配在鏈接過程,每一個.o為后綴的文件生成后都會有對應的符號表,對于add.o文件和test.o文件如下:一般符號標記錄的是函數名和全局變量或靜態變量。

在這里插入圖片描述

因為test.c文件中的n和Add是外部符號,在鏈接前并不確定這些外部符號的具體地址,系統會隨機分配一個虛假的地址;有了各自文件的符號表就可以進行符號的決議和重定位。

在這里插入圖片描述

通過以上過程確定最終的符號表,再通過鏈接庫的鏈接就可以生成可執行程序,可以通過以下的指令

//因為需要test.o和Add.o文件進行鏈接,此時有了test.o文件,再生成一個Add.o的文件gcc -c Add.c -o Add.o

在這里插入圖片描述
在這里插入圖片描述

有了test.o和Add.o文件就可以通過鏈接庫鏈接生成可執行程序,使用以下指令

//生成一個test.exe的可執行程序
gcc test.o Add.o -o test

在這里插入圖片描述
在這里插入圖片描述

6.運行

運行過程需要在運行時環境下進行,可執行程序的運行必須先將程序植入內存,在操作系統中,一般由操作系統完成;調用函數時會開辟運行時堆棧(即函數棧幀的創建),一般函數是從main函數進入,在開辟過程會保存局部變量和函數的地址,全局或靜態變量會存儲于靜態區,直到函數銷毀而銷毀,最后隨main函數的結束而終止程序 ,并輸出結果。

對應可執行程序在cmd指令中直接輸入文件名后回車即可輸出結果:

test.exe

在這里插入圖片描述

以上內容只是編譯和鏈接的大概介紹,如果對編譯鏈接想要進一步的了解,可以參考以下書籍:

《程序員的自我修養》

其它推薦書籍:高質量c/c++編程

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/83901.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/83901.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/83901.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

傳統業務對接AI-AI編程框架-Rasa的業務應用實戰(5)--Rasa成型可用 rasa服務化部署及識別意圖后的決策及行為

此篇接續上一篇 傳統業務對接AI-AI編程框架-Rasa的業務應用實戰&#xff08;4&#xff09;--Rasa成型可用 針對業務配置rasa并訓練和部署 上一篇我們已經讓Rasa準確識別了我們自然語言指令的開票和查詢發票的意圖和實體。 # 開具發票場景 用戶輸入&#xff1a;開具一張1000元…

MajicTryOn(基于wanvideo的虛擬試穿項目)

網絡結構 Attention模塊詳解 左邊服裝通過qwen2.5-VL-7B來生成詳細的服裝描述&#xff1b;線條提取器產生相應的線條map&#xff1b;garment和line map通過vae轉換為潛在空間特征&#xff0c;然后分別經過patchfier,最后通過zero proj得到Garment Tokens和Line Tokens;右邊是di…

JAVA-什么是JDK?

1.JDK 的定義 JDK&#xff08;Java Development Kit&#xff09;是 Java 開發工具包&#xff0c;是 Oracle 官方提供的用于開發、編譯和運行 Java 應用程序的核心工具集。它包含了編寫 Java 程序所需的編譯器、調試工具、庫文件以及運行時環境&#xff08;JRE&#xff09;。 2…

Palo Alto Networks Expedition存在命令注入漏洞(CVE-2025-0107)

免責聲明 本文檔所述漏洞詳情及復現方法僅限用于合法授權的安全研究和學術教育用途。任何個人或組織不得利用本文內容從事未經許可的滲透測試、網絡攻擊或其他違法行為。使用者應確保其行為符合相關法律法規,并取得目標系統的明確授權。 對于因不當使用本文信息而造成的任何直…

分布式光纖傳感(DAS)技術應用解析:從原理到落地場景

近年來&#xff0c;分布式光纖傳感&#xff08;Distributed Acoustic Sensing&#xff0c;DAS&#xff09;技術正悄然改變著眾多傳統行業的感知方式。它將普通的通信光纜轉化為一個長距離、連續分布的“聽覺傳感器”&#xff0c;對振動、聲音等信號實現高精度、高靈敏度的監測。…

獨家首發!低照度環境下YOLOv8的增強方案——從理論到TensorRT部署

文章目錄 引言一、低照度圖像增強技術現狀1.1 傳統低照度增強方法局限性1.2 深度學習-based方法進展 二、Retinexformer網絡原理2.1 Retinex理論回顧2.2 Retinexformer創新架構2.2.1 光照感知Transformer2.2.2 多尺度Retinex分解2.2.3 自適應特征融合 三、YOLOv8-Retinexformer…

96. 2017年藍橋杯省賽 - Excel地址(困難)- 進制轉換

96. Excel地址&#xff08;進制轉換&#xff09; 1. 2017年藍橋杯省賽 - Excel地址&#xff08;困難&#xff09; 標簽&#xff1a;2017 省賽 1.1 題目描述 Excel 單元格的地址表示很有趣&#xff0c;它使用字母來表示列號。 比如&#xff0c; A 表示第 1 列&#xff0c;…

EtherNet/IP轉DeviceNet協議網關詳解

一&#xff0c;設備主要功能 疆鴻智能JH-DVN-EIP本產品是自主研發的一款EtherNet/IP從站功能的通訊網關。該產品主要功能是連接DeviceNet總線和EtherNet/IP網絡&#xff0c;本網關連接到EtherNet/IP總線中做為從站使用&#xff0c;連接到DeviceNet總線中做為從站使用。 在自動…

Druid連接池實現自定義數據庫密碼加解密功能詳解

Druid連接池實現自定義數據庫密碼加解密功能詳解 在企業級應用開發中&#xff0c;數據庫密碼的明文存儲是一個顯著的安全隱患。Druid作為阿里巴巴開源的高性能數據庫連接池組件&#xff0c;提供了靈活的密碼加密與解密功能&#xff0c;允許開發者通過自定義邏輯實現數據庫密碼…

生成 Git SSH 證書

&#x1f511; 1. ??生成 SSH 密鑰對?? 在終端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;執行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ??參數說明??&#xff1a; -t rsa&#x…

Java并發編程實戰 Day 12:阻塞隊列與線程協作

【Java并發編程實戰 Day 12】阻塞隊列與線程協作 開篇 歡迎來到“Java并發編程實戰”系列的第12天&#xff01;今天我們將深入探討阻塞隊列&#xff08;BlockingQueue&#xff09;及其在線程協作中的應用。阻塞隊列是Java并發編程中一個非常重要的工具&#xff0c;它不僅簡化…

Linux 前后端項目問題排查命令手冊

一、系統資源監控類命令? 1. CPU 資源排查? top - 動態實時監控進程? top [選項] 常用選項: -d 2 # 每2秒刷新一次 -H # 顯示線程信息 -p 1234 # 僅監控PID為1234的進程 輸出解讀:? %Cpu(s):總 CPU 使用率,用戶態 + 內核態?KiB Mem:內…

Git 3天2K星標:Datawhale 的 Happy-LLM 項目介紹(附教程)

引言 在人工智能飛速發展的今天&#xff0c;大語言模型&#xff08;Large Language Models, LLMs&#xff09;已成為技術領域的焦點。從智能寫作到代碼生成&#xff0c;LLM 的應用場景不斷擴展&#xff0c;深刻改變了我們的工作和生活方式。然而&#xff0c;理解這些模型的內部…

vue3前端實現導出Excel功能

前端實現導出功能可以使用一些插件 我使用的是xlsx庫 1.首先我們需要在vue3的項目中安裝xlsx庫。可以使用npm 或者 pnpm來進行安裝 npm install xlsx或者 pnpm install xlsx2.在vue組件中引入xlsx庫 import * as XLSX from xlsx;3.定義導出實例方法 const exportExcel () …

【C++特殊工具與技術】優化內存分配(一):C++中的內存分配

目錄 一、C 內存的基本概念? 1.1 內存的物理與邏輯結構? 1.2 C 程序的內存區域劃分? 二、棧內存分配? 2.1 棧內存的特點? 2.2 棧內存分配示例? 三、堆內存分配? 3.1 new和delete操作符? 4.2 內存泄漏與懸空指針問題? 4.3 new和delete的重載? 四、智能指針…

DeepSeek 賦能智慧能源:微電網優化調度的智能革新路徑

目錄 一、智慧能源微電網優化調度概述1.1 智慧能源微電網概念1.2 優化調度的重要性1.3 目前面臨的挑戰 二、DeepSeek 技術探秘2.1 DeepSeek 技術原理2.2 DeepSeek 獨特優勢2.3 DeepSeek 在 AI 領域地位 三、DeepSeek 在微電網優化調度中的應用剖析3.1 數據處理與分析3.2 預測與…

Redis配合唯一序列號實現接口冪等性方案

1.原理 可以在客戶端每次請求服務端的時候&#xff0c;客戶端請求中攜帶一個短時間內唯一不重復的序列號來確保其唯一性&#xff0c;這個序列號常見的幾種形式有&#xff1a;基于時間戳、用戶ID和隨機數的組合&#xff1b;基于請求的來源與客戶端生成的唯一序列號組合 2.方案…

代碼安全規范1.1

命令注入是指應用程序執行命令的字符串或字符串的一部分來源于不可信賴的數據源&#xff0c;程序沒有對這 些不可信賴的數據進行驗證、過濾&#xff0c;導致程序執行惡意命令的一種攻擊方式。 例 1 &#xff1a;以下代碼通過 Runtime.exec() 方法調用 Windows 的 dir 命…

Jenkins實現自動化部署Springboot項目到Docker容器(Jenkinsfile)

Jenkins實現自動化部署Springboot項目到Docker容器 引言:為什么需要自動化部署? 在軟件開發中,頻繁的手動部署既耗時又容易出錯。通過 Docker + Jenkins + Git 的組合,您可以實現: ? 一鍵部署:代碼推送后自動構建和部署?? 環境一致性:Docker 確保開發、測試、生產環…

第二屆智慧教育與計算機技術國際學術會議(IECT 2025)

在數字化浪潮中&#xff0c;智慧教育與計算機技術的深度融合正重構教育生態。智能教學系統打破傳統課堂的單向灌輸模式&#xff0c;通過機器學習分析學習數據&#xff0c;為學生生成個性化學習路徑&#xff0c;推動被動接受向主動探索轉型。這對教育體系提出核心訴求&#xff1…