分文件編程:
- 好處:分模塊編程思想,功能和責任劃分清楚便與調試,main函數簡潔,代碼易于閱讀。
- 編程時頭文件有的是使用<>這個符號括起來的,有的是" "使用的是雙引號,使用尖括號括起來默認從/user/include/下面去找頭文件或者是/user/local/include/下面去找,而使用雙引號是默認從當前文件路徑去找。
一個小栗子(兩個數相加):
- mainadd.c文件
#include<stdio.h>
#include"addfunc.h"
int main()
{int a,b,sum;printf("input first number:\n");scanf("%d",&a);printf("input second number:\n");scanf("%d",&b);sum=add(a,b);printf("sum is %d\n",sum);return 0;
}
- addfunc.c文件,這個文件里面主要是函數體,函數的內部代碼在這個文件里面寫。
int add(int number1,int number2)
{int sum;sum=number1+number2;return sum;
}
- addfunc.h文件代碼,這個文件主要是函數的聲明,addfunc.h這個文件在main函數頭文件里面要被包含。
int add(int number1,int number2);
- 然后執行指令:
gcc mainadd.c addfunc.c -o add
進行編譯
首先了解一下gcc編譯器的工作流程:
Linux靜態庫、動態庫(共享庫)詳解:
- 在項目開發過程中,經常出現優秀代碼重用現象,又或者提供給第三方功能模塊卻又不想讓其看到源代碼,這些時候,通常的做法是將代碼封裝成庫或者框架,生成的靜態庫要和頭文件同時發布。
- 靜態庫特點: 靜態庫在程序編譯時會被連接到目標代碼中,程序運行時將不再需要該靜態庫。靜態庫優點: 尋址方便,速度快;庫在鏈接時被打包到可執行文件中,直接發布可執行程序即可以使用;發布程序無需提供靜態庫,因為已在app中,移植方便靜態庫缺點: 靜態庫的代碼被加載到可執行程序中,因此體積過大;如果靜態庫的函數發生改變,必須重新編譯可執行程序;鏈接時完整的拷貝至可執行文件中,被多次使用就有多份冗余的拷貝;更新、部署、發布、比較麻煩。
- 動態庫特點: 動態庫的代碼是在可執行程序運行時才載入內存的,在編譯過程中僅簡單的引用,因此代碼體積較小,因此在程序運行時還需要動態庫存在。動態庫優點: 節省內存;易于更新,不用重新編譯可執行程序,運行時自動加載;鏈接時不復制,程序運行時由系統動態加載到內存,供程序使用,系統只加載一次,多個程序可以共用,節省內存。動態庫缺點: 延時綁定,速度略慢;發布程序需要提供依賴的動態庫。注意: 動態函數庫和共享函數庫是一個東西(在Linux上叫共享對象庫,文件后綴是.so在windows上叫做動態函數加載庫,文件后綴是.dll)。
- Linux中命名系統中共享庫的規則:
靜態庫的制作與使用:
- 命名規則: 靜態庫文件名的命名方式是“libxxx.a”,庫名前加”lib”,后綴用”.a”,“xxx”為靜態庫名。
- 制作過程: 原材料:源代碼.c 或者 .cpp。
- 第一步: 將.c文件生成.o,
gcc 源代碼.c -c
這里是要將功能函數的.c文件生成.o文件。就用上面的那個例子:將addfunc.c生成.o文件。
gcc addfunc.c -c得到:addfunc.o
- 第二步; 將.o 打包ar rcs 靜態庫的名字 原材料,原材料就是上面生成的.o文件,靜態庫名字盡量符合靜態庫的命名規則。
ar rcs libaddfunc.a addfunc.o得到:libaddfunc.a
- 靜態庫的使用: 當靜態庫制作完成后,此時不再需要addfunc.c這個文件了,將它移除也不會造成任何影響。但是需要addfunc.h這個文件,因為main函數里面有包含這個頭文件。當別人需要你的代碼時只需將.h和.a文件提供給他們即可。靜態庫使用格式:
gcc mainadd.c -laddfunc -L ./
若直接-l 編譯會報錯,因為-l 會優先從/urs/lib 或 /urs/local/lib 中去找,但我們想讓它優先從當前路徑去找,就要用到-L ./
。使用靜態庫時一般去掉lib和后面的.a直接-l+靜態庫的名字即可。
gcc mainadd.c -laddfunc -L ./ -o add
得到:add這個可執行文件
動態庫的生成和使用:
- 命名規則: 動態庫的命名方式與靜態庫類似,前綴相同,為“lib”,后綴變為“.so”。所以為“libaddfunc.so”
- 制作指令:
gcc -shared -fpic addfunc.c -o libxxx.so
其中-shared
是指定生成動態庫,-fpic
的作用是:作用于編譯階段,在生成目標文件時就得使用該選項,以生成位置無關的代碼。
gcc -shared -fpic addfunc.c -o libaddfunc.so
得到: libaddfunc.so
- 動態庫的使用: 動態庫的使用和靜態庫的使用方法是一樣的,
gcc mainadd.c -laddfunc -L ./ -o add
其中mainadd.c 是主函數,addfunc是動態庫的名字。
gcc mainadd.c -laddfunc -L ./ -o add
得到:add這個可執行文件
但是./add會報錯,而靜態庫生成的可執行文件卻不會報錯,
原因是動態庫在生成可執行程序時沒有把動態庫包含進去,
是在程序運行過程中臨時由目標調用動態庫,靜態庫則是已經編譯到,目標程序中了。
- 這時我們就需要將自己制作的動態庫拷貝到/user/lib/下面,因為他默認的會從/user/lib/下面去找動態庫。
sudo cp libaddfunc.so /usr/lib/
//這時候在執行就不會報錯了。
- 那么如何在程序執行的時候從當前路徑下去找動態庫呢?通過環境變量
LD_LIBRARY_PATH
指定動態庫搜索路徑,export LD_LIBRARY_PATH="/home/pi/linuxfile/file1"
但是這樣的環境變量是臨時的,當退出后還要重新設置環境變量。所以我們可以使用腳本,將export LD_LIBRARY_PATH="/home/pi/linuxfile/file1"
放到腳本里面并且添加./add這個可執行文件的名稱
,然后chmod +x start.sh
給這個腳本添加可執行的權限。
- 還可以使用
du + 庫的名稱計算文件或者可執行程序的大小
例如:du add
或者du libaddfunc.so
- 除了上面哪種方法以外,還在網上看到以下兩種方法:第一種方法:gcc + 源文件 + -L 動態庫路徑 + -l動態庫名 + -I頭文件目錄 + -o 可執行文件名
gcc main.c -L lib -l MyTest -I include -o app
然后./app
會報錯:(執行失敗,找不到鏈接庫,沒有給動態鏈接器(ld-linux.so.2)指定好動態庫 libmytest.so 的路徑)第二種方法:gcc + 源文件 + -I頭文件 + libxxx.so + -o 可執行文件名
gcc main.c -l include lib/libMyTest.so -o app
(執行成功,已經指明了動態庫的路徑) - 如何解決第一種方法中找不到鏈接庫的問題?
- 使用命令
ldd app
可以查看當前的鏈接庫情況。第一種方法:
export LD_LIBRARY_PATH=自定義動態庫的路徑(只能起到臨時作用,關閉終端后失效)LD_LIBRARY_PATH : 指定查找共享庫(動態鏈接庫)時除了默認路徑之外的其他路徑,該路徑在默認路徑之前查找。第二種方法:將上述命令寫入home目錄下的.bashrc文件中,保存后重啟終端生效(永久)第三種方法:直接將動態庫拷貝到user/lib的系統目錄下(強烈不推薦!!)第四種方法:將libmytest.so所在絕對路徑追加入到/etc/ld.so.conf文件,使用sudo ldconfig -v 更新
進入/etc/ld.so.conf.d這個文件路徑下,新建一個自己的.conf,我這里是mylib.c將動態庫的絕對路徑加進去然后使用sudo ldconfig -v
更新,就可以運行可執行文件了。
Linux環境變量詳解:
- 環境變量的含義: 環境變量一般是指操作系統中指定操作系統運行環境的一些參數。它相當于一個指針,想要查看變量的值,需要加上“$”。
- 環境變量的分類: 按作用的范圍: 分在Linux中的變量,可以分為環境變量和本地變量:①環境變量:相當于全局變量,存在于所有的Shell中,具有繼承性;②本地變量:相當于局部變量只存在當前Shell中,本地變量包含環境變量,非環境變量不具有繼承性。 按生存周期分: ①永久:需要修改配置文件,變量永久生效;②暫時:使用export定義,關閉Shell后失效。
- 環境變量的組織方式: 每個程序都有一張環境表,環境表是一個指針數組,每個指針指向一個以‘\0’結尾的環境字符串。Main函數的第三個參數就是環境表地址。
常見的環境變量: - PATH: 變量指定命令的搜索路徑。
使用指令
echo $PATH
:可以查看在當前目錄下PATH的值。它表示在當前目錄下執行的每一條指令的搜索路徑,每個目錄以冒號隔開。當執行一條指令時,系統就會從系統文件中去尋找,找到了就執行;否則不執行。
-
HOME: 該變量指定用戶的主工作目錄,即用戶登錄到Linux系統時,默認的目錄。 這個環境變量一個變量,它的值隨著用戶的不同而不同。
普通用戶下的主工作目錄
sudo -s進入超級用戶權限
, 超級用戶下的主工作目錄 -
LOGNAME: 該變量指定顯示用戶的登錄名。
-
HOSTNAME: 該變量指定主機名
-
SHELL: 該變量指定用戶當前使用的解析器。
修改和顯示環境變量的命令 :
-
echo: 該命令用于顯示某個環境變量的值。
-
env : 該命令指定顯示所有的環境變量和值。
-
set: 顯示系統中已經存在的shell變量,以及設置shell變量的新變量值。使用set更改shell特性時,符號"+“和”-"的作用分別是打開和關閉指定的模式。set命令不能夠定義新的shell變量。如果要定義新的變量,可以使用declare命令以變量名=值的格式進行定義即可。
-
使用
declare
命令定義一個新的環境變量"mylove
",并且將其值設置為"Visual C++",輸入如下命令:declare mylove='Visual C++' #定義新環境變量
再使用set命令將新定義的變量輸出為環境變量,輸入如下命令:set -a mylove #設置為環境變量
執行該命令后,將會新添加對應的環境變量。用戶可以使用env命令和grep命令分別顯示和搜索環境變量"mylove",輸入命令如下:env | grep mylove #顯示環境變量值
-
export : 該命令指定設置一個新的環境變量。注意:環境變量一般用英文字母大寫加下劃線表示。
-
unset : 該命令指定清除環境變量。
- readonly : 該命令用于設置只讀環境變量,將環境變量MY_ENV設置為只讀模式后,就不能在對它進行修改了,直到用戶退出登錄后才失效。
5、存放環境變量的文件
幾個文件的作用:
- /etc/profile 該文件的作用是當用戶登錄時獲取系統的環境變量,只獲取一次。
- /etc/bashrc 當執行完/etc/profile文件后,用戶想打開bash Shell就會讀取該文件。如果想每次打開bash Shell后都執行某些操作,可以在該文件中設置。
- ~/.bash_profile 每個用戶都可使用該文件輸入專用于自己使用的shell信息。當用戶登錄時,該文件僅僅執行一次,默認情況下,它設置一些環境變量,執行用戶的.bashrc文件。單個用戶此文件的修改只會影響到他以后的每一次登陸系統。因此,可以在這里設置單個用戶的特殊的環境變量或者特殊的操作,那么它在每次登陸的時候都會去獲取這些新的環境變量或者做某些特殊的操作,但是僅僅在登陸時。
- ~/.bashrc 該文件包含專用于單個人的bash shell的bash信息,當登錄時以及每次打開一個新的shell時,該該文件被讀取。單個用戶此文件的修改會影響到他以后的每一次登陸系統和每一次新開一個bash。因此,可以在這里設置單個用戶的特殊的環境變量或者特殊的操作,那么每次它新登陸系統或者新開一個bash,都會去獲取相應的特殊的環境變量和特殊操作。
- ~/.bash_logout 當每次退出系統(退出bash shell)時,執行該文件。
環境變量部分參考這篇博文