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