1. 程式人生 > >linux高階程式設計day02 筆記 (轉)

linux高階程式設計day02 筆記 (轉)

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]); //打印出40munmap(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.cmain()
{
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可執行檔案