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