Linux系统编程入门

文章详细介绍了Linux下如何制作静态库和动态库,包括gcc编译命令和打包过程。同时,提到了Makefile的使用方法,以及gdb调试工具的几个关键指令如list、break、info、delete和disable。此外,还深入解析了Linux系统IO函数,特别是fopen与open的关系,以及read、write等函数的使用,并展示了文件复制的示例代码。
摘要由CSDN通过智能技术生成

1.静态库制作

gcc -c add.c div.c mult.c sub.c -I ../include/;  //-c编译汇编但不链接,获得-o文件
ar rcs libcalc.a add.o div.o mult.o sub.o        //把库libcalc.a和.o文件打包成静态库libcalc.a
gcc main.c -o app -I ./include/ -L ./lib -l calc //-I查找头文件,-L查找库路径,-l加载使用库

2.动态库制作

gcc -c fpic add.c div.c mult.c sub.c -I ../include
gcc -shared add.o div.o mult.o sub.o libcalc.so //libcalc.so和.o文件打包得到动态库libcalc.so
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH: /home/Linux/lesson06/lilrary/lib //告知系统库搜索路径
gcc -o main.c app -I ./include -L ./lib -l calc

3.静态库和动态库的区别

静态库:

静态库的名字形式为 libxxx.a,前缀是lib,后缀名为.a。

静态库是在链接阶段完成的,将函数库和-o文件打包得到静态库;

程序运行时使用静态库,与函数库无关系;

静态库浪费空间,因为所有相关的文件和库函数打包在一起,但没有外部依赖,直接就可以运行。

动态库:

动态库的名字形式为 libxxx.so,前缀是lib,后缀名为.so。

动态库是在程序运行阶段完成,把库函数的链接载入直到到程序运行阶段使用。

动态库也叫做共享库,动态库在内存中只存在一份,可以被多个进程共享。(动态库与共享内存相比较,动态库不能实现进程间通信)

动态库不需要拷贝到程序中,不会影响程序大小,使用动态库需要依赖外部环境。

4、Makefile

格式:

目标:依赖

命令(shell命令)

目标:最终要生成的文件,可以是Object File,也可以是执行文件。

依赖:要生成目标所需要的文件或是目标。

命令:通过执行命令对依赖操作生成目标

vim Makefile //终端操作,进入Makefile文件中
app : sub.o add.o mult.o div.o main.o
gcc sub.o add.o mult.o div.o main.o -o app
sub.o : sub.c
gcc sub.c -c sub.o
add.o : add.c
gcc add.c -c add.o
mult.o : mult.c
gcc mult.c -c mult.o
div.o: div.c
gcc div.c -c div.o
main.o : main.c
gcc main.c -c mian.o
make //终端操作,执行Makefile

5、gdb调试

list指令,查看代码。可以指定行数、函数名、文件名等操作。

break指令,设置断点。break 行号/函数名/文件名。还可以设置条件断点:比如在for循环中,设置断点停在循环变量等于某个值时。

info指令,查看断点(i b)。

delete指令,删除断点。删除的是断点编号。

disable指令,失效断点。失效的是断点编号。

6、Linux系统IO函数

1) fopen与open的关系:

open是ANSIC标准中的C语言库函数,在不同的系统中应该调不同的内核Api(open是Linux、Unix系统调用函数,返回的是一个指向文件结构的指针。在Linux中,fopen调用open。

2)Linux下读取一个文件的过程

读取一个文件(read)需要IO引擎、VFS、Page Cache高速缓存、通用管理模块、IO调度层等配合完成。

IO引擎(用户层):选择读取文件的库函数,例如sync引擎的read函数、psync引擎的pread函数。进行系统调用到达内核层。

VFS虚拟文件系统:Linux 上抽象一个通用的文件系统模型,对我们提供一组通用的接口,让我们不用在乎 具体文件系统的实现。

Page Cache高速缓存:Linux 就可以把一些磁盘上的文件数据保留在内存中,当用户要访问的文件正好存在于Page Cache内,则直接把数据从内核态拷贝到用户进程的内存中就可以了。如果不存在,那么会申请一个新页,发出缺页中断,然后用磁盘读取到的内容来填充它 ,下次直接使用。

文件系统:文件系统里提供对 VFS 的具体实现。

通用块层:提供一个统一的接口让供文件系统实现者使用,而不用关心不同设备驱动程序的差异,实现出来的文件系统就能用于任何的块设备(机械硬盘、磁盘、U盘)。

IO调度层:从全局出发,尽量让整体磁盘 IO 性能最大化。

驱动程序:驱动程序向磁盘控制发出读取命令控制。

磁盘:控制器读取硬盘数据,填充到Page Cache中的新页框

IO函数:

open函数

int open(const char* pathname, int flags) //打开文件
int open(const char* pathname, int flags, mode_t mode) //创建一个新文件,最终权限 = mode & ~umask

参数:

    pathname:文件的绝对路径或者当前路径下文件名

    flags:文件操作权限,O_RDONLY  O_WRONLY  O_RDWR

    mode:r=4,w=2,x=1

返回值:

    成功,返回一个文件描述符fd

    失败,返回-1

read函数

int read(int fd, void* buf, int count)

参数:

    fd:文件描述符,open得到

    buf:读取数据存放的地方,读取数组地址

    count:指定数组大小

返回值:

    成功,>0实际读取的字节数,=0文件读取完了

    失败,返回-1

write函数

int write(int fd, void *buf, int count)

参数:

    fd:文件描述符,open得到的

    buf:往磁盘写入的数据

    count:要写的数据的实际的大小sizeof(buf)

返回值:

    成功,返回实际写入的字节数

    失败,返回-1,并设置errno

//将test.txt文件内容复制到cpy.txt文件
//1.通过open打开test.txt文件
int srcfd = open(test.txt, O_RDONLY);
if(srcfd == -1) {
  perror("open");
  return -1;
}
//2.新建一个文件copy.txt
int desfd = open(copy.txt, O_RDWR | O_CREAT, 0664);
if(desfd == -1) {
   perror("open");
   return -1;
}
//3.进行拷贝(频繁读写操作)
int len = 0;
char buf[1024] = {0};
//char *a = "abcd";"abcd"存放在常量存储区,通过指针只可以访问字符串常量,而不可以改变它
//char a[20] = "abcd";"abcd"存放在栈,可以通过指针去访问和修改数组内容
while(len = read(srcfd, buf, sizeof(char)) > 0) {
    //read中使用sizeof(char),整个数组都用于读,之前的初始化都会被覆盖
    write(dstfd, buf, len);
}

//4.关闭文件
close(srcfd);
close(dstfd);

注意事项:write()函数从buf写数据到fd中时,若buf中数据无法一次性读完,那么第二次读buf中数据时,其读位置指针(也就是第二个参数buf)不会自动移动,需要程序员来控制,而不是简单的将buf首地址填入第二参数即可。例如可按如下格式实现读位置移动:write(fp, p1+len, (strlen(p1)-len))。 这样write第二次循环时便会从p1+len处写数据到fp, 之后的也一样。由此类推,直至(strlen(p1)-len)变为0
 

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值