brk/sbrk
維護(hù)一個位置。 brk/sbrk改變這個位置。
brk改變絕對位置
sbrk改變相對位置
昨天的補充:
永遠(yuǎn)記住:C的基本類型就那幾種。
所有全新類型都是使用typedef重新定義的。
類型重定義的好處:
1. 維護(hù)方便
2. 便于移植(每個系統(tǒng)中都用同一個名,不用修改)
3. 容易理解
一、 映射虛擬內(nèi)存
沒有任何額外維護(hù)數(shù)據(jù)的內(nèi)存分配 mmap/munmap
1. 函數(shù)說明:
void *mmap(
void *start, //指定映射的虛擬地址,如果為0,則由系統(tǒng)指定開始位置
size_t length,//指定映射空間的大小。 pagesize的倍數(shù)
int prot, //映射的權(quán)限 PROT_NONE PROT_READ PROT_WRITE PROT_WRITE PROT_EXEC
int flags, //映射的方式
int fd, //文件描述符號
offset_t off //文件中的映射開始位置(必須是0或pagesezi的倍數(shù))
);
關(guān)于映射的方式flags:
內(nèi)存映射:又叫匿名映射,最后兩個參數(shù)無效
文件映射:映射到某個文件
只有文件映射,最后兩個參數(shù)才有效
MAP_ANONYMOUS:內(nèi)存映射
MAP_SHAREDMAP_PRIVATE:二選一,文件映射
2. 案例:
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
int *p = mmap(
NULL,
getpagesize(),
PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_SHARED,
0,
0);
*P = 20;
*(p+1) = 30;
*(p+2) = 40;
printf("%d\n", p[2]); //打印出40
munmap(p, 4096);
}
3. 總結(jié):
選擇什么樣的內(nèi)存管理方法?
STL
new
malloc小而多的數(shù)據(jù)
brk/sbrk同類型的大塊數(shù)據(jù),動態(tài)移動指針
mmap/munmap 控制內(nèi)存的訪問/使用文件映射/控制內(nèi)存共享
二、編程工具與動態(tài)庫
1. gcc
2. make
3. gdb
4. 其他工具
5. 動態(tài)庫(共享庫)
1. gcc
-o 輸出文件名
-O-O1-O2-O3//編譯優(yōu)化
-g-g1-g2-g3//產(chǎn)生調(diào)試信息
-Wallerror//-Wall 顯示所有警告-Werror 將警告當(dāng)成錯誤提示
-w//關(guān)閉所有警告
-c//只編譯不連接,產(chǎn)生 .o文件(目標(biāo)文件)
-E//預(yù)編譯
-S//匯編。 產(chǎn)生 .s文件(匯編文件)
編譯4過程是 -E(產(chǎn)生.i) -c(產(chǎn)生.o) -S(產(chǎn)生.s) 自動調(diào)用連接器ld -D//在命令行定義宏 (宏可以在代碼中定義,也可以在命令行上定義)
-x//指定編譯的語言類型 C, C++, .S(匯編), none(自動判定)
-std=c89 使用標(biāo)準(zhǔn)C89
-std=c99 使用標(biāo)準(zhǔn)C99
三、 靜態(tài)庫的編譯
1. 編譯過程 (*.a) a是achieve的縮寫
1.1 編譯成目標(biāo)文件
-static 可選
gcc -c -static 代碼文件.c //生產(chǎn)可用于歸檔的目標(biāo)代碼:代碼文件.0
1.2 歸檔成靜態(tài)庫
ar工具 (常用-r -t選項)
ar -r 靜態(tài)庫 被歸檔的文件名(上一步代碼文件.o)
ar -r add.a add.o
nm工具(查看庫中所蘊含的函數(shù)列表)
nm 靜態(tài)庫或動態(tài)庫或目標(biāo)文件或執(zhí)行文件
1.3 使用靜態(tài)庫
gcc 代碼文件 靜態(tài)庫
小例子:
使用靜態(tài)庫完成如下程序
輸入一個菱形半徑,打印菱形
輸入整型封裝成IOTool
菱形打印封裝成Graphic
計劃:
1. 實現(xiàn)輸入
2. 實現(xiàn)菱形
3. 編譯靜態(tài)庫
4. 調(diào)用靜態(tài)庫
//iotool.c
#include <stdio.h>
int inputInt(const char *info)
{
int r; //返回值
printf("%s:", info);
scanf("%d", &r);
return r;
}
//graphic.c
#include <stdio.h>
void diamond(int r)
{
int x, y;
for(y=0; y<=2*r; y++)
{
for(x=0; x<=2*r; x++)
{
if(y == x+r || y == x-r ||y == -x+r || y == -x+3*r)
{
printf("*");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
編譯: gcc -c -static iotool.c
gcc -c -static graphic.c
ar -r demo1.a iotool.o graphic.o
ar -t demo1.a //相當(dāng)于nm demo1.a
//main.c
main()
{
int r = inputInt("輸入菱形半徑:");
diamond(r);
}
編譯: gcc main.c demo1.a -o main
執(zhí)行:./main
把靜態(tài)庫作為代碼的一部分來編譯
總結(jié):
1. 什么是庫?
函數(shù)等代碼封裝的二進(jìn)制已經(jīng)編譯的歸檔文件
2. ar歸檔工具
3. 采用庫的方式管理代碼優(yōu)點:
容易組織代碼
復(fù)用
保護(hù)代碼版權(quán)
4. 靜態(tài)庫的“靜態(tài)”的含義:
編譯好的程序運行的時候不依賴庫
庫作為程序的一部分編譯連接
5. 靜態(tài)庫的本質(zhì)就是目標(biāo)文件的集合(歸檔)6. -static可選
2. 庫的規(guī)范與約定
庫命名規(guī)則:
lib庫名.a.主版本號.副版本號.批號
一般就寫“lib庫名.a”就行了。
ar -r libdemo2.a iotool.o graphic.o
庫的使用規(guī)則
-l庫名
-L庫所在的目錄
gcc main.c -o main -l demo2 -L.
四、 動態(tài)庫的編譯
1. 什么是動態(tài)庫(共享庫)
動態(tài)庫是可以執(zhí)行的,靜態(tài)庫不能執(zhí)行
但動態(tài)庫沒有main,不能獨立執(zhí)行
動態(tài)庫不會連接成程序的一部分
程序執(zhí)行時,必須需要動態(tài)庫文件
2. 工具
ldd查看程序需要調(diào)用的動態(tài)庫 ,ldd只能查看可執(zhí)行文件(共享庫文件或elf文件)
nm (查看庫中的函數(shù)符號)
3. 動態(tài)庫的編譯
3.1編譯
-c -f pic(可選) (-f 指定文件格式 pic 位置無關(guān)代碼)
3.2 連接
-shared
編譯:gcc -c -fpic iotool.c
gcc -c -fpic graphic.c
(非標(biāo)準(zhǔn))gcc -shared -odemo3.so iotool.o graphic.o
(標(biāo)準(zhǔn))gcc -shared -olibdemo4.so iotool.o graphic.o
4. 使用動態(tài)庫
gcc 代碼文件名 動態(tài)庫文件名
gcc 代碼文件名 -l庫名 -L動態(tài)庫所在的路徑
gcc main.c -ldemo4 -L. -o main
標(biāo)準(zhǔn)命名規(guī)則:
lib庫名.so
lib庫名.a
問題:
4.1 執(zhí)行程序怎么加載動態(tài)庫?
4.2 動態(tài)庫沒有作為執(zhí)行程序的一部分,為什么連接需要制定動態(tài)庫及目錄?
因為連接器需要確認(rèn)函數(shù)在動態(tài)庫中的位置
動態(tài)庫的加載:
1. 找到動態(tài)庫
2. 加載動態(tài)庫到內(nèi)存(系統(tǒng)實現(xiàn))
3. 映射到用戶的內(nèi)存空間(系統(tǒng)實現(xiàn))
動態(tài)庫查找規(guī)則:
/lib
/user/lib
LD_LIBRARY_PATH環(huán)境變量指定的路徑中找
設(shè)置當(dāng)前路徑為環(huán)境變量:(
自己定義的庫最好設(shè)置好目錄,或者放到上述公共目錄)export LD_LIBRARY_PATH=.:~:..:~Walle
緩沖機制:
系統(tǒng)把lib:/user/lib:LD_LIBRARY_PATH里的文件加載到緩沖
/sbin/ldconfig -v 刷新緩沖so中的搜索庫的路徑
小練習(xí):
輸入兩個數(shù),計算兩個數(shù)的和。
要求:輸入與計算兩個數(shù)的和封裝成動態(tài)庫調(diào)用
五、 使用libdl.so庫
動態(tài)庫加載原理
動態(tài)庫中函數(shù)的查找已經(jīng)封裝成哭libdl.so
libdl.so里面有4個函數(shù):
dlopen//打開一個動態(tài)庫
dlsym//在打開的動態(tài)庫里找一個函數(shù)
dlclose//關(guān)閉動態(tài)庫
dlerror//返回錯誤
//dldemo.c
#include <dlfcn.h>
main()
{
void *handle = dlopen("./libdemo4.so", RTLD_LAZY);
void (*fun)(int) = dlsym(handle, "diamond");
fun(5);
dlclose(handle);
}
gcc dldemo.c -o main -ldl
ldd main
./main
總結(jié):
1. 編譯連接動態(tài)庫
2. 使用動態(tài)庫
3. 怎么配置讓程序調(diào)用動態(tài)庫
4. 掌握某些工具的使用 nm ldd lddconfig objdump strit(去掉多余的信息)
六、 工具make的使用與makefile腳本
背景:
make編譯腳本解釋
編譯腳本makefile
make -f 腳本文件 目標(biāo)
腳本文件:
1. 文本文件 (例如 demo.mk)
2. 基本構(gòu)成語法
基本單位目標(biāo)target
目標(biāo)名:依賴目標(biāo)
\t目標(biāo)指令
\t目標(biāo)指令
//demo.mk
demo:iotool.c graphic.c main.c
gcc iotool.c -c
gcc graphic.c -c
gcc iotool.o graphic.o -shared -o libdemo.so
gcc main.c -ldemo -L. -o main
make -f demo.mk demo 會生產(chǎn)main可執(zhí)行文件