您的位置:首页 > 其它

day02

2016-04-13 18:10 651 查看

0 回顾

brk/sbrk

维护一个位置。 brk/sbrk改变这个位置。

brk改变绝对位置

sbrk改变相对位置

昨天的补充:

永远记住:C的基本类型就那几种。

所有全新类型都是使用typedef重新定义的。

类型重定义的好处:

1. 维护方便

2. 便于移植(每个系统中都用同一个名,不用修改)

3. 容易理解

1 映射虚拟内存

没有任何额外维护数据的内存分配 mmap/munmap

1.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:二选一,文件映射

1.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);
}


1.3 总结

选择什么样的内存管理方法?

STL

new

malloc小而多的数据

brk/sbrk同类型的大块数据,动态移动指针

mmap/munmap 控制内存的访问/使用文件映射/控制内存共享

2 编程工具与动态库

gcc

make

gdb

其他工具

动态库(共享库)

2.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

3 静态库的编译

3.1 编译过程 (*.a)

a是achieve的缩写

3.1.1 编译成目标文件

-static 可选

gcc -c -static 代码文件.c //生产可用于归档的目标代码:代码文件.0

3.1.2 归档成静态库

ar工具 (常用-r -t选项)

ar -r 静态库 被归档的文件名(上一步代码文件.o)

ar -r add.a add.o

nm工具(查看库中所蕴含的函数列表)

nm 静态库或动态库或目标文件或执行文件

3.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可选

3.2 库的规范与约定

库命名规则:

lib库名.a.主版本号.副版本号.批号

一般就写“lib库名.a”就行了。

ar -r libdemo2.a iotool.o graphic.o

库的使用规则

-l库名

-L库所在的目录

gcc main.c -o main -l demo2 -L.

4 动态库的编译

4.1 什么是动态库(共享库)

动态库是可以执行的,静态库不能执行

但动态库没有main,不能独立执行

动态库不会连接成程序的一部分

程序执行时,必须需要动态库文件

4.2 工具

ldd查看程序需要调用的动态库 ,ldd只能查看可执行文件(共享库文件或elf文件)

nm (查看库中的函数符号)

4.3 动态库的编译

4.3.1 编译

-c -f pic(可选) (-f 指定文件格式 pic 位置无关代码)

4.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
4000

4.4 使用动态库

gcc 代码文件名 动态库文件名

gcc 代码文件名 -l库名 -L动态库所在的路径

gcc main.c -ldemo4 -L. -o main

标准命名规则:

lib库名.so

lib库名.a

问题:

1)执行程序怎么加载动态库?

2)动态库没有作为执行程序的一部分,为什么连接需要制定动态库及目录?

因为连接器需要确认函数在动态库中的位置

动态库的加载:

①. 找到动态库

②. 加载动态库到内存(系统实现)

③. 映射到用户的内存空间(系统实现)

动态库查找规则:

/lib

/user/lib

LD_LIBRARY_PATH环境变量指定的路径中找

设置当前路径为环境变量:(自己定义的库最好设置好目录,或者放到上述公共目录)

export LD_LIBRARY_PATH=.:~:..:~Walle

缓冲机制:

系统把lib:/user/lib:LD_LIBRARY_PATH里的文件加载到缓冲

/sbin/ldconfig -v 刷新缓冲so中的搜索库的路径

小练习:

输入两个数,计算两个数的和。

要求:输入与计算两个数的和封装成动态库调用

5 使用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);
}


总结:

1) 编译连接动态库

2)使用动态库

3)怎么配置让程序调用动态库

4)掌握某些工具的使用 nm ldd lddconfig objdump strit(去掉多余的信息)

6 工具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可执行文件

计算素数的例子

//input.c
#include <stdio.h>

int inputInt()
{
int a;
scanf("%d",&a);
return a;
}
//primer.c
int isPrimer(int a)
{
int i;
for(i=2;i<a;i++)
{
if(a%i==0)
{
return 0;
}
}
return 1;
}
//demo.c
#include <stdio.h>
main()
{
int a=inputInt();
int r=isPrimer(a);
if(r==1)
{
printf("%d是素数!\n",a);
}
else
{
printf("%d是合数!\n",a);
}
}
//demo.mk
demo:
gcc -c -fpic input.c
gcc -c -fpic primer.c
gcc -shared -olibdemo.so input.o primer.o
gcc demo.c -ldemo -L. -omain


执行:export LD_LIBRARY_PATH=.

make -f demo.mk demo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: