轉自:http://www.cnblogs.com/zhangming-blog/p/4020535.html
1.malloc工作原理: malloc使用一個數據結構(鏈表)維護分配空間
鏈表的構成:分配的空間/上一個空間數據/下一個空間/空間大小等信息.
對malloc分配的空間不要越界訪問.因爲容易破壞後臺維護結構.導致malloc/free/calloc/realloc不正常工作.
2.有關__stdcall __cdecl __fastcall
<1>.決定函數棧壓棧的參數順序. <2>.決定函數棧的清空方式 <3>.決定了函數的名字轉換方式.
__cdecl
這是編譯器默認的函數調用轉換方式,它可以處理可變參數的函數調用。參數的入棧順序是從右向左。在函數運行結束後,由調用函數負責清理入棧的參數。在編譯時,在每個函數前面加上下劃線(_),沒有函數名大小寫的轉換。即_functionname
每一個調用它的函數都包含清空堆棧的代碼,所以產生的可執行文件大小會比調用_stdcall函數的大。函數採用從右到左的壓棧方式。注意:對於可變參數的成員函數,始終使用__cdecl的轉換方式。
__fastcall
有一些函數調用的參數被放入ECX,EDX中,而其它參數從右向左入棧。被調用函數在它將要返回時負責清理入棧的參數。在內嵌彙編語言的時候,需要注意寄存器的使用,以免與編譯器使用的產生衝突。函數名字的轉換是:@functionname@number沒有函數名大小寫的轉換,number表示函數參數的字節數。由於有一些參數不 需要入棧,所以這種轉換方式會在一定程度上提高函數調用的速度。
__stdcall
函數參數從右向左入棧,被調用函數負責入棧參數的清理工作。函數名轉換格式如下:_functionname@number
3.虛擬內存: 虛擬地址與物理地址映射的時候有一個基本單位: 4k 一個內存頁. 如果虛擬地址沒有映射到物理地址,試圖用指針訪問必定發生段錯誤
4.分配釋放內存函數: int brk(void *end);//分配空間,釋放空間
void *sbrk(int size);//返回空間地址
sbrk(int size)
sbrk與brk後臺系統維護一個指針.
指針默認是null.
調用sbrk,判定指針是否是0,是:得到大塊空閒空間的首地址初始化指針.
5.映射虛擬內存函數:
mmap(分配)/unmap(釋放)
void *mmap(
void *start,//指定映射的虛擬地址 0由系統指定開始位置)
size_t length,//映射空間大小 pagesize倍數
int prot,//映射權限 PROT_NONE | PROT_READ PROT_WRITE PROT_EXEC
int flags,//映射方式
int fd,//文件描述符號
offset_t off);//文件中的映射開始位置(必須是pagesize的倍數)
映射方式:
內存映射:匿名映射。
文件映射:映射到某個文件 只有文件映射最後兩個參數有效。
MAP_ANONYMOUS
MAP_SHARED MAP_PRIVATE(二選一)
6.編譯工具與動態庫:
<1> gcc
-o 輸出文件名
-O -O0 -O1 -O2 -O3 編譯優化
-g -g0 -g1 -g2 -g3 產生調試信息
-W all error
-Wall 顯示所有警告
-Werror 把警告當錯誤
-w 關閉警告
-c 只編譯不連接
-E 預編譯
-S 彙編
-D 在命令行定義宏。
在代碼中定義宏
在命令行定義宏
-x 指定編譯的語言類型
c++
c
.S
none 自動判定
-std=C89
C99
編譯過程:-E -c -S 自動調用連接器
連接器 ld
補充:
.c
.cpp
.CC
.h
.hpp
.o
.a
.so
.i 預編譯文件
.s 彙編文件
<2>
1.編譯過程(*.a achieve)
1.1.編譯成目標文件
-static 可選
gcc -c -static 代碼文件.c
1.2.歸檔成靜態庫
ar工具
ar -r || -t
ar -r 靜態庫文件 被歸檔的文件
nm工具(察看函數符號表)
nm 靜態庫或者動態庫或者目標文件或者執行文件
1.3.使用靜態庫
gcc 代碼 靜態庫
2.庫的規範與約定
庫命名規則:
lib庫名.a.主版本號.副版本號.批號
lib庫名.a
庫使用規則
-l 庫名
-L 庫所在目錄
<3>.動態庫的編譯
1.什麼是動態庫?(共享庫)
動態庫是可以執行,靜態庫不能執行
但動態庫沒有main,不能獨立執行。
動態庫不會連接成程序的一部分。
程序執行的時候,必須需要動態庫文件。
2.工具
ldd 察看程序需要調用的動態庫
ldd 只能察看可執行文件.
readelf -h 察看執行程序頭.
nm 察看庫中的函數符號
3.動態庫的編譯
3.1.編譯
-c -fpic(可選)
3.2.連接
shared
4.使用動態庫
gcc 代碼 動態庫文件名
gcc 代碼 -l庫名 -L動態庫所在路徑
標準命名規則:
lib庫名.so
lib庫名.a
-l 庫名 -L 庫所在路徑
<5>使用libdl.so庫
動態庫加載的原理 動態庫中函數的查找已經封裝成庫libdl.so
dlopen 打開一個動態庫
dlsym 在打開動態庫找一個函數
dlclose 關閉動態庫
//dlerror 返回錯誤
7.make工具的使用:
(1). vi demo.mk
(2)編輯: demo:
gcc -c -fpic test1.c
gcc -c -fpic test2.c
gcc test1.o test2.o -shared -o libtest.so
gcc main.c -l test -o main -L.
(3).執行demo.mk文件:
make -f demo.mk demo
注意:須將libtest.so 庫文件拷貝到/lib或usr/lib目錄下
8.使用main方法參數獲得環境變量:(直接獲取可以用env)
int main(int argc,char*argv[],char**arge)
{
while(*arge)
{
printf("%s\n",*arge);
arge++;
}
}
9.IO基礎
<1>.認識內核對象
不允許訪問內核設備和內存,
但可以通過內核系統函數去訪問.
對每個內核對象進行編號ID.
如果訪問內核對象,只能通過ID.
編程模型:
申請得到一個ID
在內核系統函數中使用ID得到對應內核對象數據
<2>.怎麼訪問文件
使用函數,傳遞一個文件,系統打開文件,加載文件數據,
返回一個ID.
使用函數,傳遞ID,得到數據.
使用函數傳遞ID,告訴系統釋放文件.
ID:文件描述符號.file description (fd)
每個程序執行的時候都有一個目錄,存放打開的文件描述符號
<3>.每個程序默認打開三個文件設備:
0:標準輸入
1:標準輸出
2:錯誤輸出
<4>.操作文件描述符號
ssize_t write(int fd,
void *buf,//要寫入內核對象的數據
size_t size);//寫入數據大小
返回:
>0 實際寫入的數據
-1 寫入錯誤
ssize_t read(int fd,
void *buf,//返回數據的空間
size_t size);//空間大小
返回:
>0:實際讀取的數據
=0:碰到文件結束符號EOF (ctrl+d)
-1:讀取錯誤
建議:
0:輸入
1:輸出
2:錯誤輸出
<5>.linux系統下文件的類型:
目錄文件d
普通文件f
字符設備文件c
塊設備文件b
軟連接文件l
管道文件p
socket文件s