Linux工具學習之【gcc/g++】

📘前言

書接上文,我們已經學習了 Linux 中的編輯器 vim 的相關使用方法,現在已經能直接在 Linux 中編寫C/C++代碼,有了代碼之后就要嘗試去編譯并運行它,此時就可以學習一下 Linux 中的編譯器 gcc/g++ 了,我們一般使用 gcc 編譯C語言,g++ 編譯C++(當然 g++ 也可編譯C語言),這兩個編譯器我們可以當作一個來學習,因為它們的命令選項都是通用的,只是編譯對象不同。除了編譯器相關介紹外,本文還會庫、自動化構建工具、提權等知識,一起來看看吧

?📘正文
📖gcc/g++ 命令

在接下來的學習中,我們以 gcc 為例,因為兩者選項都是通用的,所以也就相當于間接學習了 g++ ,這個編譯器上手還是很簡單的,選項也不是很多

注意: 如果命令失效,很有可能是沒有下載 gcc/g++ ,需要自行下載安裝 gcc 與 g++

📃-o 目標文件

gcc 源文件 默認會將代碼編譯鏈接并生成可執行文件 a.out ,當然前提是代碼沒問題,所以這樣看來編譯一個文件還是很簡單的

$ gcc 源文件	//直接編譯源文件,生成默認可執行文件為 a.out

?可能有的人不想讓它生成默認的?a.out?,想生成為指定文件,沒有問題,直接通過?-o?選項就能實現
注意:-o?選項后面必須緊跟生成的目標文件,這個選項可以放在源文件后面,也可以放在前面

$ gcc test.c -o OK	//編譯生成文件為 OK
$ gcc -o OK test.c	//這種寫法也是可以的

?在我們使用?gcc/g++?時,都可以通過?-o?選項生成指定文件?

📃-E 預處理

在C語言學習階段,我們學習了源文件變成可執行文件的過程,即預處理-編譯-匯編-鏈接,當時因為沒有學習Linux,沒法很好的展示各個環節的現象,今天可以來詳細看看

首先是第一步:預處理,又稱預編譯

會進行頭文件展開、刪除注釋、替換宏、執行條件編譯等操作
目的是生成一個純粹的C代碼程序
經過預處理后的文件后綴為 .i
我們可以直接通過 gcc 中的 -E 命令,使編譯器在執行完預處理后停下來配合 -o 生成指定文件,這樣我們就可以觀察到上面所提到的這些現象了。

$ gcc -E test.c -o test.i	//預處理后的文件后綴為 .i 此時仍然是C語言

📃-S 編譯

下面進入第二個步驟:編譯

進行語法分析、詞法分析、語義分析、符號匯總等,然后將合法的代碼轉為匯編代碼
編譯目的是生成匯編代碼
譯后生成的文件后綴為 .s
編譯階段比較重要的一步就是符號匯總,它會各種符號匯總起來,方便后續符號表的形成,符號表用于各種函數間的相互調用

我們可以通過 -S 選項,使 gcc 在執行完編譯階段后就停下來,配合 -o 生成文件 test.s

$ gcc -S test.c -o test.s	//可以直接從 test.c 開始執行,也可以從上一步中的 test.i 執行

?📃-c 匯編

接下來進入第三步:匯編

主要任務是將匯編代碼轉為二進制,并生成符號表
二進制文件的格式是 elf ,此時 vim 查看為亂碼
生成的文件后綴為 .o
因為計算機只能看懂二進制,所以將代碼轉為二進制是必須進行的操作,除此之外,還有一個重要步驟:生成符號表

關于符號表

這個東西相當于函數獨一無二的地址,在Linux 中,C語言的符號表比較簡單,通常是 _函數名,比如 _Add ;C++更詳細一些,通常為 _Z函數名長度+函數名+參數1+參數2 ,比如常見的 Add 函數,生成的符號表為 _Z3Addii ,這里的參數是兩個整型,這也是C++支持重載,而C語言不支持重載的根本原因,畢竟C語言中兩個重名的函數生成的符號表是完全一樣的,區分不了
可以通過 -c 選項使 gcc 在執行完匯編階段后就停下來,指定保存文件為 test.o

查看生成的 test.o 文件,可以用 readelf 這個工具,缺失的可以去下載

$ gcc -c test.c -o test.o	//從源文件重新開始編譯,生成 test.o 二進制文件
$ gcc -c test.s -o test.o	//從上一步中生成的 test.s 文件開始編譯,兩者效果是一樣的//關于查看 elf 格式的文件
$ readelf -a test.o	//可以通過軟件,觀察到符號表等信息

📃gcc 鏈接

下面是最后一步:鏈接

進行合并段表、將符號表進行合并和重定位等
將程序運行所需的各種函數鏈接起來,包括與庫函數的鏈接,Linux 中一般是動態鏈接,鏈接后生成可執行文件,此時的文件也是 elf 的格式
gcc 默認生成的可執行文件為 a.out,我們可以指定生成任意文件

$ gcc test.c -o myfile	//生成可執行文件為 myfile
$ gcc test.o -o myfile	//繼上一次生成的二進制文件執行鏈接,也是沒有問題的

?📃小結

關于各個命令選項可以巧記為?ESc?這是鍵盤上的一個鍵,忘記了可以看看
還有各個選項對應生成的文件后綴為?iso


📖庫
1. 標準庫的位置:
  • 標準庫頭文件:標準庫的頭文件(如 stdio.hstring.hstdlib.h 等)通常存放在 /usr/include 目錄下。這些頭文件提供了庫函數的聲明和宏定義函數的具體實現都在庫中了。它們是編寫 C 程序時必須包含的文件。

  • 標準庫的實現:標準庫的實際實現(即函數的定義和邏輯)并不在 /usr/include 目錄下,而是通常存放在系統的庫目錄中,比如 /lib/usr/lib。這些庫可能是 靜態庫.a 為擴展名)或 動態庫.so 為擴展名)

📃動態庫

動態庫 即通過 動態鏈接 的庫,動態庫 又稱 共享庫,因為 動態庫 中的內容是被所有程序共享的,簡言之 動態庫 中的代碼只需要存在一份,程序需要使用時,直接通過對應位置調用就行了

Linux 中默認使用 動態鏈接 的方式,我們可以通過指令 ldd 最終生成的文件 來查看最終生成文件的鏈接情況

$ ldd 最終生成的文件	//查看文件的鏈接情況

?libXXX.so 是動態鏈接的標志

其中 lib 是前綴
.so 是后綴
去掉前綴與后綴,就是最終調用的庫
舉例:libc.so 去掉前綴與后綴,最終為 c ,可以看出文件最終調用的是C語言共享庫,即 動態鏈接

動態鏈接 主要依賴不同函數在庫中的位置信息進行調用,只有一份代碼庫,比較節省空間

我們還可以通過 file 命令查看文件詳細信息

$ file 最終生成的文件	//查看文件的詳細情況
?📃靜態庫

除了 動態庫 外,還有 靜態庫 ,采用 靜態鏈接 的方式;靜態鏈接 不同與 動態鏈接 共享的方式,如果程序調用 靜態庫 ,會將自己所需要的代碼 拷貝至程序中 ,完成拷貝后,后續不需要再調用 靜態庫

如果想采用 靜態鏈接 鏈接的方式編譯程序,需要在編譯時加上 -static 選項,當然前提是得有 靜態庫,沒有的可以通過 yum install -y glibc-static 下載 靜態庫

當然我們也可以通過 ldd 最終生成的文件 查看是否為 靜態鏈接

$ yum install -y glibc-static	//下載靜態庫
$ gcc test.c -o myfile-static -static	//采取靜態鏈接的方式編譯程序
$ ldd 最終生成的文件	//查看文件的鏈接方式

動態庫 vs 靜態庫的優缺點對比:
區別動態庫靜態庫
調用方式通過函數位置(動態鏈接)進行調用直接將需要的函數拷貝至程序中(靜態鏈接)
依賴性(運行時)需要依賴于動態庫文件,運行時必須能找到對應的 .so 文件不依賴外部庫,程序可以獨立運行
空間占用共享動態庫中的代碼,多個程序共享同一個庫,節省空間每個程序都包含庫代碼,導致文件較大
加載速度調用時需要加載庫并進行鏈接,加載速度慢直接運行,程序中已經包含了庫的代碼,加載速度快
更新更新庫時,無需重新編譯程序,方便管理和維護更新庫時需要重新編譯程序,管理較為繁瑣
版本兼容性可能會遇到版本不兼容問題(“DLL Hell”)一旦編譯完成,不受庫版本變化影響
內存占用多個程序可以共享同一個庫文件,節省內存每個程序都占用一份內存空間

動態庫的優點:

  1. 共享代碼:動態庫可以在多個程序之間共享,節省磁盤空間和內存。對于大型程序和多個程序共享同一個庫的情況,動態庫非常有用。

  2. 程序小巧:因為動態庫不包含在每個可執行文件中,所以生成的程序文件較小。

  3. 更新簡便:如果庫的功能有更新,只需要替換庫文件,無需重新編譯所有依賴這個庫的程序。這使得系統升級和維護更加方便。

  4. 內存共享:多個程序運行時,可以共享動態庫中的代碼和數據,節省內存。

動態庫的缺點:

  1. 加載速度較慢:由于程序在運行時需要加載和鏈接動態庫,調用速度相對較慢,特別是在頻繁調用庫函數的情況下。

  2. 運行時依賴性:程序需要在運行時找到并加載正確的動態庫版本。如果缺少動態庫或版本不兼容,程序可能無法正常運行(例如,缺少 .so 文件)。

  3. 版本問題:如果系統中多個程序依賴于同一個動態庫,而庫的版本發生變化時,可能會導致“版本不兼容”(DLL Hell)的問題。

靜態庫的優點:

  1. 獨立性:靜態庫在編譯時就已鏈接到可執行文件中,程序不依賴外部的庫文件,減少了運行時的復雜性。

  2. 加載速度快:靜態庫的代碼已經包含在程序中,程序啟動時不需要額外加載庫,加載速度較快。

  3. 無需擔心版本問題:由于靜態庫在編譯時就已經鏈接到程序,程序和庫的版本不會再發生兼容性問題。

靜態庫的缺點:

  1. 空間占用大:每個程序都需要包含靜態庫的副本,因此生成的可執行文件較大,浪費存儲空間。

  2. 更新麻煩:如果需要更新庫,必須重新編譯程序,這對于大型項目或多個依賴同一庫的項目來說,管理和更新較為麻煩。

  3. 內存占用多:每個運行的程序都加載靜態庫的代碼,占用更多內存,而動態庫則可以被多個程序共享內存。

總結:

  • 動態庫適用于:

    • 需要多個程序共享同一份代碼庫的場景,尤其是在內存和磁盤空間有限的情況下。

    • 程序開發周期較長,庫需要經常更新,且更新后不想重新編譯所有依賴程序的情況。

    • 對更新靈活性要求較高,且能夠接受可能出現的加載速度和依賴問題。

  • 靜態庫適用于:

    • 對程序啟動速度要求較高,且不依賴外部庫的場景。

    • 程序體積可以接受,且不需要頻繁更新庫的情況。

    • 獨立部署的應用程序,不想擔心外部庫的兼容性問題。

選擇使用動態庫還是靜態庫,通常要根據具體項目的需求、系統資源以及維護成本來決定。如果項目中有多個依賴共享的庫文件,動態庫往往是更好的選擇;而如果項目需要更高的執行效率或獨立性,靜態庫可能更適合。

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

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

相關文章

微信小程序文字混合、填充動畫有效果圖

效果圖 .wxml <view class"text" style"--deg:{{deg}}deg;"><view>混合父級顏色</view> </view> <view class"fill {{status?action:}}">文字顏色填充</view> <button bind:tap"setStatus"…

C++:PTA L1-006 連續因子

一個正整數 N 的因子中可能存在若干連續的數字。例如 630 可以分解為 3567&#xff0c;其中 5、6、7 就是 3 個連續的數字。給定任一正整數 N&#xff0c;要求編寫程序求出最長連續因子的個數&#xff0c;并輸出最小的連續因子序列。 輸入格式&#xff1a; 輸入在一行中給出一…

分享:批量提取圖片文字并自動命名文件,ocr識別圖片指定區域并重命名文件名工具,基于WPF和騰訊OCR識別的接口的視線方案

一、項目背景 在處理大量圖片時,常常需要從圖片中提取特定區域的文字信息,并依據這些信息對圖片進行重命名。例如,在檔案管理領域,大量紙質文件被掃描成圖片后,需要從圖片中提取關鍵信息(如文件編號、日期等)來重命名圖片,以便后續的檢索和管理;在電商領域,商家可能…

匯編語言中的數據

在匯編語言中&#xff0c;程序都是由指令流構成的&#xff0c;而指令一般是由操作符和操作數組成的&#xff0c;操作符是CPU用來完成某項功能的操作&#xff0c;而操作數是操作符所處理加工的對象。比如&#xff1a;add eax, 42&#xff0c;add是執行一個加法運算的操作符&…

C++17 信號量模擬實現

C17 信號量模擬實現 一、實現原理 C17 標準庫沒有原生信號量(C20才有)&#xff0c;但可以通過 std::mutex std::condition_variable 模擬實現。以下是核心邏輯&#xff1a; #include <mutex> #include <condition_variable>class CountingSemaphore { private:…

C++ 網絡層接口設計與實現:基于 Socket 編程

在網絡編程中&#xff0c;網絡層是 OSI 七層模型中負責將數據從源節點傳輸到目的節點的關鍵層次。在 C 中&#xff0c;網絡層的功能通常通過 Socket 編程接口來實現。Socket 提供了一種抽象機制&#xff0c;允許應用程序通過網絡發送和接收數據。本文將詳細介紹如何在 C 中使用…

uniapp中uni-easyinput 使用@input 不改變綁定的值

只允許輸入數字和字母 使用input 正則replace后賦值給A 遇到問題: 當輸入任意連續的非法字符時, 輸入框不變. 直到輸入一個合法字符非法字符才成功被過濾. <uni-forms-item label"納稅人識別號" name"number"><uni-easyinput v-model"numb…

Docker安裝hoppscotch

Docker安裝hoppscotch 1 簡介 1.1 Hoppscotch?系統 ?Hoppscotch?是一個輕量、高效的[API開發生態系統&#xff0c;開源于2020年&#xff0c;原名Postwoman&#xff0c;后更名為Hoppscotch。它基于Node.js構建&#xff0c;支持多種HTTP請求方法&#xff0c;包括GET、POST、…

1.Axum 與 Tokio:異步編程的完美結合

摘要 深入解析 Axum 核心架構與 Tokio 異步運行時的集成&#xff0c;掌握關鍵原理與實踐技巧。 一、引言 在當今的軟件開發領域&#xff0c;高并發和高性能是衡量一個系統優劣的重要指標。對于 Web 服務器而言&#xff0c;能夠高效地處理大量并發請求是至關重要的。Rust 語言…

CSS偽元素

偽元素 偽元素 用于在元素的內容前后或特定部分插入虛擬元素&#xff0c;并為其添加樣式&#xff0c;無需修改 HTML 結構。 語法&#xff1a;使用雙冒號 ::&#xff08;現代規范&#xff09; 以下是一些常見的CSS偽元素的示例&#xff1a; 1.::before &#xff1a; 在元素內…

easyexcel使用模板填充excel坑點總結

1.單層map設置值是{屬性}&#xff0c;那使用兩層map進行設置值&#xff0c;是不是可以使用{屬性.屬性}&#xff0c;以為取出map里字段只用{屬性}就可以設置值&#xff0c;那再加個.就可以從里邊map取出對應屬性&#xff0c;沒有兩層map寫法 填充得到的文件打開報錯 was empty (…

在Ubuntu服務器上部署xinference

一、拉取鏡像 docker pull xprobe/xinference:latest二、啟動容器&#xff08;GPU&#xff09; docker run -d --name xinference -e XINFERENCE_MODEL_SRCmodelscope -p 9997:9997 --gpus all xprobe/xinference:latest xinference-local -H 0.0.0.0 # 啟動一個新的Docker容…

三周年創作紀念日

文章目錄 回顧與收獲三年收獲的五個維度未來的展望致謝與呼喚 親愛的社區朋友們&#xff0c;大家好&#xff01; 今天是 2025 年 4 月 14 日&#xff0c;距離我在 2022 年 4 月 14 日發布第一篇技術博客《SonarQube 部署》整整 1,095 天。在這條創作之路上&#xff0c;我既感慨…

Redis——五種數據類型

目錄 前言 1.String 1.1RAW編碼 1.2EMBSTR編碼 1.3 INT編碼 2.List 3.Set 3.1 InSet編碼轉化成Dict編碼 4.ZSet 4.1結合SkipList和HT實現 4.2使用ZipList實現 4.3編碼轉換 4.4 ZipList排序功能 5.Hash 5.1Hash底層存儲結構 6.Redis數據結構和數據類型關系圖 前言…

zookeeper啟動報錯have small server identifier

解決方案&#xff1a; 1、查看myid是否有重復 2、查看server.X 與myid的X是否一致 3、啟動順序為myid從小到大的服務器順序

#Linux動態大小裁剪以及包大小變大排查思路

1 動態庫裁剪 庫分為動態庫和靜態庫&#xff0c;動態庫是在程序運行時才加載&#xff0c;靜態庫是在編譯時就加載到程序中。動態庫的大小通常比靜態庫小&#xff0c;因為動態庫只包含了程序需要的函數和數據&#xff0c;而靜態庫則包含了所有的函數和數據。靜態庫可以理解為引入…

消息隊列生產者投遞的高可靠性與一致性保障方案

在構建高可靠分布式系統時&#xff0c;確保業務數據庫與消息隊列&#xff08;MQ&#xff09;之間的一致性是一項核心挑戰。尤其當使用 Kafka 作為消息隊列中間件時&#xff0c;如何避免“數據庫寫入成功&#xff0c;但消息發送失敗”或“消息重復發送”等問題&#xff0c;成為系…

Formality:Bug記錄

相關閱讀 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 本文記錄博主在使用Synopsys的形式驗證工具Formality中遇到的一個Bug。 Bug復現 情況一 // 例1 module dff (input clk, input d_in, output d_out …

通信算法之267 : DJI無人機 云哨 DroneID 640ms

DJI 無人機 與DroneID 轉 *** 載 0x01 摘要 消費級無人機可以用于高級航拍、物流和人道主義救援等等。但是其廣泛使用給安全、安保和隱私帶來了許多風險。例如&#xff0c;攻擊方可能會使用無人機進行監視、運輸非法物品&#xff0c;或通過侵入機場上方的封閉空域造成經濟損…

論壇測試報告

作者前言 &#x1f382; ??????&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ?&#x1f382; 作者介紹&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…