Linux系統編程深度解析:C語言實戰指南

文章一覽

  • 前言
  • 一、gcc編譯系統
    • 1.1 文件名后綴
    • 1.2 C語言編譯過程
    • 1.3 gcc命令行選項
  • 二、gdb程序調試工具
    • 2.1 啟動gdb和查看內部命令
    • 2.2 顯示源程序和數據
      • 2.2.1 顯示和搜索源程序
      • 2.2.2 查看運行時數據
    • 2.3 改變和顯示目錄或路徑
    • 2.4 控制程序的執行
      • 2.4.1 設置斷點
      • 2.4.2 顯示斷點
      • 2.4.3 刪除斷點
      • 2.4.4 運行程序
      • 2.4.5 程序的單步跟蹤和連續執行
      • 2.4.6 函數調用
    • 2.5 其他常用命令

前言

在數字世界的浩瀚星海中,Linux操作系統如同一顆璀璨的恒星,以其開源、穩定和強大的特性,照亮了無數開發者的編程之路。而C語言,作為最接近硬件層面的高級編程語言,以其無與倫比的性能和靈活性,成為了構建Linux系統的基石。在這個充滿挑戰與機遇的時代,掌握Linux環境下的C程序設計,不僅是技術追求,更是一種對極致性能和系統控制的渴望。
現在,讓我們一起啟程,深入Linux與C語言的神秘世界。

一、gcc編譯系統

1.1 文件名后綴

目前Linux平臺上最常用的C語言編譯系統是gcc(GNU Compiler Collection)

常用文件名后綴及其表示的文件類型:

文件名后綴文件類型
.cC源文件
.i預處理后的C源文件
.ii預處理后的C++源文件
.hC或C++頭文件
.C .cc .cp .cpp .c++ .cxxC++源文件
.s匯編程序文件
.S必須預處理的匯編程序文件
.o目標文件
.a靜態鏈接庫
.so動態鏈接庫

1.2 C語言編譯過程

  1. 預處理階段預處理程序(Preprocessor)讀取C語言源文件,對其中以“#”開頭的指令(偽指令)和特殊符號進行處理。 偽指令主要包括文件包含、宏定義和條件編譯指令

  2. 編譯階段編譯程序(Compiler)對預處理之后的輸出文件進行詞法分析和語法分析,試圖找出所有不符合語法規則的部分。在確定各成分都符合語法規則后,將其“翻譯”為功能等價的中間代碼表示或者匯編代碼。

  3. 匯編過程匯編程序(Assembler)把匯編語言代碼翻譯成目標機器代碼的過程。

  4. 連接階段將一個文件中引用的符號(如變量或函數調用)與該符號在另外一個文件中的定義連接起來,從而使有關的目標文件連成一個整體,最終成為可被操作系統執行的可執行文件。連接模式分為靜態連接和動態連接

1.3 gcc命令行選項

$ gcc f1.c f2.c (針對C語言源程序) 執行完成后,生成默認的可執行文件a.out。

按照選項作用所對應的編譯階段,可將gcc的選項分為四組:預處理選項編譯選項優化選項連接選項

  1. 預處理選項
選項格式功能
-C在預處理后的輸出中保留源文件中的注釋
-D name預定義一個宏name,而且其值為1
-D name=definition預定義一個宏name,并指定其值為definition所指定的值。其作用等價于在源文件中使用宏定義指令:#define name definition。但-D選項比宏定義指令的優先級高,它可以覆蓋源文件中的定義
-U name取消先前對name的任何定義,不管是內置的,還是由-D選項提供的
-I dir指定搜索頭文件的路徑dir。先在指定的路徑中搜索要包含的頭文件,若找不到,則在標準路徑(/usr/include, /usr/lib及當前工作目錄)上搜索
-E只對指定的源文件進行預處理,不做編譯,生成的結果送到標準輸出

例:

 # 添加“-I /root”參數編譯,/root為my.h文件位置gcc 1-3.c -o 1-3 -I /root 
  1. 編譯程序選項
選項格式功能
-c只生成目標文件,不進行連接。用于對源文件的分別編譯
-S只進行編譯,不做匯編,生成匯編代碼文件格式,其名與源文件相同,但擴展名為.s
-o file將輸出放在文件file中。如果未使用該選項,則可執行文件放在a.out中
-g指示編譯程序在目標代碼中加入供調試程序gdb使用的附加信息
-v在標準出錯輸出上顯示編譯階段所執行的命令,即編譯驅動程序及預處理程序的版本號
  1. 優化程序選項

優化分為對中間代碼的優化和針對目標代碼生成的優化。

  1. 連接程序選項
選項格式功能
object -file -name不以專用后綴結尾的文件名就認為是目標文件名或庫名。連接程序可以根據文件內容來區分目標文件和庫
-c -S -E如果使用其中任何一個選項,那么都不運行連接程序,而且目標文件名不應該用做參數
-llibrary連接時搜索由library命名的庫。連接程序按照在命令行上給定的順序搜索和處理庫及目標文件。實際的庫名是liblibrary.a
-static在支持動態連接的系統中,它強制使用靜態鏈接庫,而阻止連接動態庫;而在其他系統中不起作用
-Ldir把指定的目錄dir加到連接程序搜索庫文件的路徑表中,即在搜索-l后面列舉的庫文件時,首先到dir下搜索,找不到再到標準位置下搜索
-Bprefix該選項規定在什么地方查找可執行文件、庫文件、包含文件和編譯程序本身數據文件
-o file指定連接程序最后生成的可執行文件名稱為file,不是默認的a.out
  • Linux下庫文件的命名有一個約定,所有的庫名都以lib開頭。因此,在-l選項所指定的文件名前自動地插入lib。并且約定,以.a(歸檔,archive)結尾的庫是靜態庫,以**.so(共享目標,shared object)結尾的庫是動態庫**。

  • 生成靜態庫的方法實際上可分為兩步:

① 將各函數的源文件編譯成目標文件。例如:

\$ gcc -c f1.c f2.c f3.c -o game.o

由此可得到各源文件的目標文件game.o

② 使用ar工具將目標文件收集起來,放到一個歸檔文件中。例如:

\$ ar -rcs \$HOME/lib/libgame.a game.o

  • 生成靜態庫以后,就可在編譯C語言源文件時指明對它進行搜索、連接,例如:

\$ gcc f1.c f2.c f3.c -o mygame -static -L$HOME/lib -lgame

例:

gcc編譯靜態庫

#gcc 編譯靜態庫并調用,演示如何將 add.c 打包成一個靜態庫來供 main.c 調用.
#1.首先將add.c編譯成目標文件。
gcc  -c  add.c  -o  add.o
# 2.ar 打包靜態庫,將 add.o 打包成 libadd.a,
#參數 [-crv] :–c表示建立備存文件,- r表示將文件插入備存文件中,-v表示程序執行時顯示詳細的信息
ar  -crv  libadd.a  add.o
#3.使用靜態庫 libadd.a編譯main.c, [-L./] 表示將當前目錄加到靜態庫的搜索路徑
gcc  main.c  -L./  libadd.a  -o  main2
#4.執行
./main2

gcc 編譯動態庫

#1.編譯位置無關的目標文件 add.o,因為動態庫動態加載到內存中的位置不確定,所以需要編譯位置無關
gcc -fPIC -c add.c -o add.o
打包成動態庫,
#2.如果不加 sudo 會提示沒有權限,如果不指定/usr/lib/文件夾,會在執行時提示
#error while loading shared libraries:libadd.so: cannot open shared object file: No such file or directory
sudo gcc -shared add.o -o /usr/lib/libadd.so
#3.編譯
sudo gcc -0 main3 main.c -L /usr/lib/ -ladd
#4.執行
./main3

二、gdb程序調試工具

程序中的錯誤按其性質可分為三種:

(1)編譯錯誤,即語法錯誤。主要是程序代碼中有不符合所用編程語言語法規則的錯誤。

(2)運行錯誤。如對負數開平方,除數為0,循環終止條件永遠不能達到等 。

(3)邏輯錯誤。這類錯誤往往是編程前對求解的問題理解不正確或算法不正確引起的,它們很難查找。查找程序中的錯誤,診斷其準確位置,并予以改正,這就是程序調試。程序調試分為人工查錯機器調試

gdb主要幫助用戶在調試程序時完成四方面的工作

(1)啟動程序,可以按用戶要求影響程序的運行行為。

(2)使運行程序在指定條件處停止。

(3)當程序停止時,檢查它出現了什么問題。

(4)動態改變程序的執行環境,這樣就可以糾正一個錯誤的影響,然后再糾正其他錯誤。

2.1 啟動gdb和查看內部命令

為了發揮gdb的全部功能,需要在編譯源程序時使用-g選項:

gcc  -g  prog.c  -o  prog  #(針對C語言源程序prog.c)
gcc  -g  program.cpp  -o  program # (針對C++源程序program.cpp)

啟動gdb的常用方法有:

(1)以一個可執行程序作為gdb的參數:

$ gdb prgm

(2)同時以可執行程序和core文件作為gdb的參數:

$ gdb prgm core

啟動gdb后就顯示其提示符:(gdb),并等待用戶輸入相應的內部命令。

用戶可以利用命令quit終止其執行,退出gdb環境。

2.2 顯示源程序和數據

2.2.1 顯示和搜索源程序

(1)顯示源文件

利用list命令可以顯示源文件中指定的函數代碼行

格式功能
list沒有參數,顯示當前行之后或周圍的10多行
list –顯示先前10行之前的10行
list [file:] num顯示源文件file中給定行號num周圍的10行。如果缺少file,則默認為當前文件。例如,list 100
list start , end顯示從行號start至end之間的代碼行。例如,list 20,38
list [file:]function顯示源文件file中指定函數function的代碼行。如果缺少file,則默認為當前文件。例如,list meng1.c:square

也可以利用set listsize命令重新設置一次顯示源程序的行數:

set listsize linenum

(2)模式搜索

格式功能
forward-search regexp從列出的最后一行開始向前搜索給定的模式regexp(即正則表達式,一個字符串的匹配模式)。例如,forward-search i=*
search regexp同上
reverse-search regexp從列出的最后一行開始向后搜索給定的模式regexp(即正則表達式,一個字符串的匹配模式)。例如,reverse-search i=??

2.2.2 查看運行時數據

(1)print命令

  • 當被調試的程序停止時,可以用print命令(簡寫為p)或同義命令inspect來查看當前程序中運行的數據。
  • print命令的一般使用格式:print [/fmt] exp

? print i (或p i) 顯示當前變量i的值。

? print i\*j (或p i\*j) 將根據程序當前運行的實際情況顯示出i*j的值。

(2)gdb所支持的運算符

①用&運算符取出變量在內存中的地址,如:

? print &i 顯示變量i的存放地址。

? print &array[i] 顯示數組array第i個元素的地址。

{ type }adrexp 表示一個數據類型為type、存放地址為adrexp的數據。

@ 是一個與數組有關的雙目運算符,使用形式如:

? print array@10 打印從array(數組名,即數組的基地址)開始的10個值。

? print array[3]@5 打印從array第三個元素開始的5個數組元素的數值。

file :: var (或者 function :: var ) 表示文件file(或者函數function)中變量var的值。例如:

? print inner::i 打印函數inner中變量i的當前值。

(3)輸出格式

由表示格式的字母(如o、x、d、u、t、f、a、i、c、s)和表示數據長度的字母(如b、w、h、g)組成。

2.3 改變和顯示目錄或路徑

(1)directory命令

? 將給定目錄dir添加到源文件搜索路徑的開頭,并且忽略先前保存的有關源文件和代碼行位置的信息。其一般格式是:

? directory [dir] 或者 dir [dir]

(2)cd命令

? cd命令將調試程序和被調試程序的工作目錄置為指定的目錄dir。其使用格式為:

? cd dir

(3)path命令

? 利用path命令可以將一個或多個目錄添加到目標文件搜索路徑的開頭。其使用格式是:

? path dirs

(4)pwd命令

? 該命令用來顯示工作目錄。

(5)show directories命令

? 該命令顯示定義的源文件搜索路徑。

(6)show paths命令

? 該命令顯示當前查找目標文件的搜索路徑。

2.4 控制程序的執行

2.4.1 設置斷點

編譯源程序時需要使用-g選項

在gdb中用break命令(其縮寫形式為b)設置斷點:

break linenum (在當前文件指定行linenum處設置斷點,停在該行開頭)

break linenum if condition (在當前文件指定行linenum處設置斷點,但僅在條件表達式condition成立時才停止程序執行)

break function (在當前文件函數function的入口處設置斷點)

break file:linenum (在源文件file的linenum行上設置斷點)

break file:function (在源文件file的函數function的入口處設置斷點)

break *address (運行程序在指定的內存地址address處停止)

break (不帶任何參數,則表示在下一條指令處停止)

斷點應設置在可執行的行上,不應是變量定義之類的語句

2.4.2 顯示斷點

info  breakpoints  [num]
info  break  [num]

2.4.3 刪除斷點

delete [bkptnums]

2.4.4 運行程序

run [args] (run簡寫是r)

2.4.5 程序的單步跟蹤和連續執行

(1)單步跟蹤

? step [N] 參數N表示每步執行的語句行數。 進入被調用函數內部執行。

? next [N] 參數N表示每步執行的語句行數。 被調用函數被當做一條指令執行。

? stepi(縮寫為si)或nexti(縮寫為ni)命令一條一條地執行機器指令。

(2)連續執行

利用continue,c或fg命令連續執行到下一個斷點

2.4.6 函數調用

call expr

? 其中,expr是所用編程語言的函數調用表達式,包括函數名實參

  • 在調試過程中,可以使用return命令強行從正在執行的函數中退出:

? return [expr]

  • 還可以使用finish命令退出函數,但它并不立即退出,而是繼續運行,直至當前函數返回

2.5 其他常用命令

1.執行shell命令

shell command-string

例如:

(gdb) shell date

2009年 03月 31日 星期二 16:47:56 CST

(gdb)

2.修改變量值

(gdb) print x=10

(gdb) set variable x=10

3.跳轉執行

jump linenum (參數linenum表示下一條語句的行號。)

jump *addr (參數 addr表示下一條代碼行的內存地址。)

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

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

相關文章

SQL優化原理與具體實例分析

一、引言 SQL(Structured Query Language,結構化查詢語言)是關系型數據庫的核心語言。在實際應用中,數據庫查詢性能往往成為系統性能瓶頸。因此,掌握SQL優化技巧對于提高數據庫查詢效率具有重要意義。本文將圍繞SQL優…

安卓藍牙掃描流程

目錄 系統廣播 流程圖 源碼跟蹤 系統廣播 掃描開啟廣播:BluetoothAdapter.ACTION_DISCOVERY_STARTED "android.bluetooth.adapter.action.DISCOVERY_STARTED";掃描關閉廣播:BluetoothAdapter.ACTION_DISCOVERY_FINISHED "android.b…

shell 編程(三)

條件測試命令 條件測試:判斷某需求是否滿足,需要有測試機制來實現 專用的測試表達式需要由測試命令輔助完成測試過程,評估布爾生命,以便用在條件性執行中 若真,則狀態碼變量$? 返回0 // echo $? 打印0 反之返回1 t…

八股(One Day one)

最近老是看到一些面試的視頻,對于視頻內部面試所提到的八股文,感覺是知道是什么,但是要說的話,卻又不知道該怎么說(要不咋稱之為八股文呢),所以就想到寫一篇八股文總結的博客,以便進…

Rust 在前端基建中的使用

摘要 隨著前端技術的不斷發展,前端基礎設施(前端基建)的建設已成為提升開發效率、保障產品質量的關鍵環節。然而,在應對復雜業務場景與高性能需求時,傳統的前端技術棧逐漸暴露出諸多不足。近年來,Rust語言…

豆包MarsCode:a替換函數

問題描述 思路分析 在這個問題中,我們的目標是將字符串中的所有小寫字母 a 替換為 "%100"。為了實現這一點,我們需要分析問題的核心需求和合理的解決方案。以下是分析和思路的詳細步驟: 1. 理解問題 給定一個字符串 s&#xff0…

人臉生成3d模型 Era3D

從單視圖圖像進行3D重建是計算機視覺和圖形學中的一項基本任務,因為它在游戲設計、虛擬現實和機器人技術中具有潛在的應用價值。早期的研究主要依賴于直接在體素上進行3D回歸,這往往會導致過于平滑的結果,并且由于3D訓練數據的限制&#xff0…

【點估計】之Python實現

點估計是一種統計推斷方法,它利用樣本數據來估計總體的未知參數。在概率論和數理統計的框架下,點估計將總體的未知參數視為一個確定的值或一個具體的點,并試圖通過樣本數據來找到這個值的最佳估計。以下是對點估計的詳細解釋: 一、定義與原理 定義:點估計是根據樣本數據估…

rust與python互通

互通三件套 rust側與python互通的三個庫: pyo3 pythonize serde pyo3 pyo3跟用Python C API寫python擴展有點類似,核心是: #[pymodule] #[pyfunction]兩個注解。前者對應Py_InitModule,后者對應PyMethodDef。 下面是其它博…

Ubuntu系統下 npm install -g tauri 報錯問題處理

處理在安裝 Tauri 時遇到的問題,可以按照以下步驟進行操作 npm install -g taurinpm warn deprecated inflight1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async …

信貸域——互聯網金融理論基礎

摘要 互聯網金融這種新興的金融業態近幾年飛速發展,規模不斷擴大,互聯網金融在對我國金融體系和經濟發展影響中所占的分量越來越重,一定程度上也推動了互聯網金融理論的發展。 互聯網金融與傳統金融都是金融,有著相近的理論基礎。…

C++軟件設計模式之享元模式(FlyWeight)

享元(Flyweight)模式的動機與意圖 動機 享元模式的主要動機是通過共享對象來減少內存使用,從而提高系統的性能。在某些情況下,系統中可能有大量細粒度的對象,這些對象具有共同的部分狀態,而這些狀態可以共…

LightGBM分類算法在醫療數據挖掘中的深度探索與應用創新(上)

一、引言 1.1 醫療數據挖掘的重要性與挑戰 在當今數字化醫療時代,醫療數據呈爆炸式增長,這些數據蘊含著豐富的信息,對醫療決策具有極為重要的意義。通過對醫療數據的深入挖掘,可以發現潛在的疾病模式、治療效果關聯以及患者的健康風險因素,從而為精準醫療、個性化治療方…

|-牛式-|

題目描述 下面是一個乘法豎式,如果用我們給定的那幾個數字來取代 * ,可以使式子成立的話,我們就叫這個式子牛式。 * * * x * * ------- * * * * * * ------- * * * * 數字只能取代 * ,當然第一位不能為 0 。 寫一個程序找…

es 3期 第18節-分頁查詢使用避坑的一些事

#### 1.Elasticsearch是數據庫,不是普通的Java應用程序,傳統數據庫需要的硬件資源同樣需要,提升性能最有效的就是升級硬件。 #### 2.Elasticsearch是文檔型數據庫,不是關系型數據庫,不具備嚴格的ACID事務特性&#xff…

STM32串口第一次接收數據時第一個字節丟失的問題

解決方法:開啟中斷之前,先清除標志位【1】。 串口清除標志位: __HAL_UART_CLEAR_PEFLAG(&huart1); HAL_UART_Receive_IT(&huart1,&RxUart, 1); 定時器清除標志位: __HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE);…

深度學習中的殘差網絡、加權殘差連接(WRC)與跨階段部分連接(CSP)詳解

隨著深度學習技術的不斷發展,神經網絡架構變得越來越復雜,而這些復雜網絡在訓練時常常遇到梯度消失、梯度爆炸以及計算效率低等問題。為了克服這些問題,研究者們提出了多種網絡架構,包括 殘差網絡(ResNet)、…

Pytorch | 從零構建EfficientNet對CIFAR10進行分類

Pytorch | 從零構建EfficientNet對CIFAR10進行分類 CIFAR10數據集EfficientNet設計理念網絡結構性能特點應用領域發展和改進 EfficientNet結構代碼詳解結構代碼代碼詳解MBConv 類初始化方法前向傳播 forward 方法 EfficientNet 類初始化方法前向傳播 forward 方法 訓練過程和測…

Vue 2 中實現雙擊事件的幾種方法

在 Vue 2 中處理用戶交互,特別是雙擊事件,是一個常見的需求。Vue 提供了一種簡潔的方式來綁定事件,包括雙擊事件。本文將介紹幾種在 Vue 2 中實現雙擊事件的方法。 1. 使用 dblclick 指令 Vue 允許你直接在模板中使用 dblclick 指令來監聽雙…

音視頻入門基礎:MPEG2-TS專題(20)——ES流簡介

《T-REC-H.222.0-202106-S!!PDF-E.pdf》第27頁對ES進行了定義。ES流是PES packets(PES包)中編碼的視頻、編碼的音頻或其他編碼的比特流。一個ES流(elementary stream)在具有且只有一個stream_id的PES packets序列中攜帶&#xff1…