map.c
#include
#include
#include
#include
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]);
munmap(p,4096);//释放内存
}
C++
STL new 最省事
C
malloc (小而多数据)
brk/sbrk (同类型的大块数据,动态移动指针) mmap/munmap(控制内存访问/使用文件映射/控制内存共享)
-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 c文件
.cpp c++
.CC c++
.h 头文件
.hpp
.o 目标文件
.a 静态库
.so 动态库
.i 预编译文件
.s 汇编文件
hong.c
int printf(const char*,...);
main()
{
printf("%d\n",NUM);
}
gcc hong.c -omain -DNUM=5; 运行main 结果:5
可以在命令行定义宏
1.编译过程(*.a achieve(归档文件))
1.1.编译成目标文件
-static 可选
gcc -c -static 代码文件.c 编译成目标文件 .o文件
ku1.c
int add(int a,int b)
{
return a+b;
}
ku2.c
int sub(int a,int b)
{
return a-b;
}
callku.c
main()
{
int r=add(45,55);
int s=sub(100,45);
}
也可以 1 gcc -static -c ku1.c 生成ku1.o
2 gcc -static -c ku2.c 生成ku2.o
1.2.归档成静态库
ar工具
ar -r
-t
ar -r 静态库文件 被归档的文件
命令行 ar -r ku.a ku1.o ku2.o 生成ku.a(静态库文件) 非标准的 建议使用下面例子的标准命名和使用静态库
执行ar -t ku.a 可以看到静态库中包含ku1.o ku2.o
nm工具(察看函数符号表)
使用方法 nm 静态库或者动态库或者目标文件或者执行文件
执行nm ku.a 可以查看到add 和 sub函数名
1.3.使用静态库
gcc 代码 静态库
gcc callku.c ku.a -omain 缩短编译时间
使用静态库完成如下程序:
输入一个菱形半径,打印菱形。
输入整数封装成IOTool
菱形的打印封装成Graphics
计划:
1.实现输入
2.实现菱形
3.编译静态库
4.调用静态库
iotool.c
#include
int inputInt(const char *info)
{
int r;
printf("%s:",info);
scanf("%d",&r);
return r;
}
#include
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");
}
}
main.c
#include
#include
main()
{
int r=inputInt("输入菱形半径");
diamond(r);
printf("%d\n",getpid());
while(1);
}
第一步 gcc -c -static iotool.c graphic.c
第二步 ar -r libdemo1.a iotool.o graphic.o
第三步 gcc main.c -ldemo -L. -omain
第四步 main执行
总结:
1.什么是库?
函数等代码封装的二进制已经编译的归档文件
2.ar归档工具
3.采用库德方式管理代码优点:
容易组织代码
复用
保护代码版权
4.静态库的静态的含义:
编译好的程序运行的时候不依赖库。
库作为程序的一部分编译连接。
5.静态库本质:
就是目标文件集合(归档)
6.-static可选
2.库的规范与约定
库命名规则:
lib库名.a.主版本号.副版本号.批号
lib库名.a
库使用规则
-l 库名
-L 库所在目录
1.什么是动态库?(共享库)
动态库是可以执行,静态库不能执行
但动态库没有main,不能独立执行。
动态库不会连接成程序的一部分。
程序执行的时候,必须需要动态库文件。
2.工具
ldd 察看程序需要调用的动态库
ldd 只能察看可执行文件(包括动态库文件).
readelf -h 察看执行程序头.
nm 察看库中的函数符号
3.动态库的编译
3.1.编译
-c -fpic(可选)
第一步 gcc -c iotool.c
第二步 gcc -c graphic.c
3.2.连接
-shared 第三步gcc -shared -olibdemo4.so iotool.o graphic.o
4.使用动态库 第四步gcc main.c -ldemo4 -L. -omain
执行程序时会发现找不到动态库 (见下面系统对动态库查找规则)
解决方法export LD_LIBRARY_PATH=.:~ 只对本shell有效
方法一 gcc 代码 动态库文件名
方法二 gcc 代码 -l库名(把lib去掉后) -L动态库所在路径
标准命名规则:
lib库名.so 动态库
lib库名.a 静态库
-l 库名 -L 库所在路径
问题:
4.1.执行程序怎么加载动态库?
4.2.动态库没有作为执行程序的一部分,为什么连接需要指定动态库以及目录?
连接器需要确定函数在动态库的中的位置
动态库的加载:
1.找到动态库 我们只能在这一步进行操作
2.加载动态库到内存
3.映射到用户的内存空间
系统对动态库查找规则:
1 到环境变量LD_LIBRARY_PATH指定的路径中查找
2 从/etc/ld.so.cache缓存文件列表中查找(该缓存文件由ldconfig工具维护)
3 /lib
4/usr/lib
缓冲机制:
linux启动的时候就把/lib:/usr/lib:LD_LIBRARY_PATH加载到缓冲ld.so.cache文件中。
/sbin/ldconfig -v 刷新缓冲中so的搜索数据
ldconfig工具简介
ldconfig是一个动态链接库管理命令,为了让动态链接库为系统所共享,还需运行动态链接库的管理命令--ldconfig。 ldconfig 命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态 链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件.缓存文件默认为 /etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表.
linux下的共享库机制采用了类似于高速缓存的机制,将库信息保存在/etc/ld.so.cache里边。
程序连接的时候首先从这个文件里边查找,然后再到ld.so.conf的路径里边去详细找。
这就是为什么修改了ld.so.conf要重新运行一下ldconfig的原因
补充一点,ldconfig在/sbin里面。
ldconfig几个需要注意的地方
1. 往/lib和/usr/lib里面加东西,是不用修改/etc/ld.so.conf的,但是完了之后要调一下ldconfig,不然这个library会找不到
2. 想往上面两个目录以外加东西的时候,一定要修改/etc/ld.so.conf,然后再调用ldconfig,不然也会找不到
比如安装了一个mysql到/usr/local/mysql,mysql有一大堆library在/usr/local/mysql/lib下面,这时 就需要在/etc/ld.so.conf下面加一行/usr/local/mysql/lib,保存过后ldconfig一下,新的library才能在 程序运行时被找到。
3. 如果想在这两个目录以外放lib,但是又不想在/etc/ld.so.conf中加东西(或者是没有权限加东西)。那也可以,就是export一个全局变 量LD_LIBRARY_PATH,然后运行程序的时候就会去这个目录中找library。一般来讲这只是一种临时的解决方案,在没有权限或临时需要的时 候使用。
4. ldconfig做的这些东西都与运行程序时有关,跟编译时一点关系都没有。编译的时候还是该加-L就得加,不要混淆了。
5. 总之,就是不管做了什么关于library的变动后,最好都ldconfig一下,不然会出现一些意想不到的结果。不会花太多的时间,但是会省很多的事。
动态库加载的原理
动态库中函数的查找已经封装成库libdl.so
dlopen 打开一个动态库
dlsym 在打开动态库找一个函数
dlerror 返回错误
dlclose 关闭动态库
dldemo.c
#include
main()
{
void *handle=dlopen("./libdemo4.so",RTLD_LAZY);
void(*fun)(int)=dlsym(handle,"diamond");
fun(5);
dlclose(handle);
}
gcc dldemo.c -omain -ldl //代码中的函数在libdl.so动态库中
总结:
1.编译连接动态库
2.使用动态库
3.怎么配置让程序调用动态库
4.掌握某些工具的使用:nm ldd lddconfig
背景:每次gcc去编译每个程序很累人
make 编译脚本解释
编译脚本Makefile
make -f 脚本文件 目标
脚本文件
1.文本文件
2.基本构成语法:
基本单位目标target
目标名:依赖目标
\t目标指令
\t目标指令
Makefile
demo: //这一行写依赖目标 次例子可不写
gcc iotool.c -c //前面是tab键绝对不可以使用空格
gcc graphic.c -c
gcc iotool.o graphic.o -shared -olibdemo.so
gcc main.c -ldemo -omain -L.
综合案例:
1.输入一个整数判定是否素数
a.input.c
primer.c
demo.c
b.make脚本
c.使用make
d.执行程序
input.c
#include
int inputInt(const char *info)
{
int a;
printf("%s:",info);
scanf("%d",&a);
return r;
}
primer.c
int isPrimer(int a)
{
int i;
for(i=2;i
main.c
#include
main()
{
int a=inputInt("请输入一个整数\n");
int r=isPrimer(a);
if(r==1)
{
printf("%d是素数!\n",a);
}
else
{
printf("%d是合数!\n",a);
}
}
compile:
gcc -c -fpic input.c
gcc -c -fpic primer.c
lnk:compile
gcc -shared -olibdemo.so input.o primer.o
demo:lnk
gcc demo.c -ldemo -L. -omain
如果执行不了 找不到动态库
export LD_LIBRARY_PATH=.
任务:
1、输入一个整数,打印这个数的Goldbach分解
所有大于等于6的偶数都可以分解成两个奇素数的和。
要求:
封装成共享库。
使用make脚本编译
2、已知"tom jack rose",写一个程序,统计单词个数
并且打印每个单词.
要求:使用共享库封装。
使用make脚本
3、输出菜单,选择:1打印菱形,2打印矩形,
选择1 , 则输出菱形(半径4)
选择2 ,则输出矩形(半径4*4)