当前位置: 首页 > news >正文

C++学习之Linux文件编译、调试及库制作

目录

1.rwx对于文件和目录的区别

2.gcc编译过程

3.数据段合并和地址回填说明

4.gcc编译其他参数

5.函数库简介

6.静态库的使用

7.动态库的简介

8.动态库制作基本流程

9.启动APP错误解决方案12

10.启动APP错误解决方案34

11.makefile一组规则

12.makefile的两个函数

13.makefile自动变量的定义和使用

14.makefile的all和clean使用

15.模式规则和静态模式规则

16.makefile的其它参数和变量使用

17.gbd调试、基础指令

18.gbd的其他指令

19.补充知识:栈帧

20.gbd中bt和frame命令


1.rwx对于文件和目录的区别

系统调用

什么是系统调用:

 由操作系统实现并提供给外部应用程序的编程接口。(Application Programming Interface,API)。是应用程序同系统之间数据交互的桥梁。

 C标准函数和系统函数调用关系。一个helloworld如何打印到屏幕。

2.gcc编译过程

fopen、fclose、fseek、fgets、fputs、fread、fwrite......

 r 只读、 r+读写

w只写并截断为0、 w+读写并截断为0

a追加只写、 a+追加读写

open/close函数  

函数原型

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

int close(int fd);

常用参数

O_RDONLY、O_WRONLY、O_RDWR    

O_APPEND、O_CREAT、O_EXCL、 O_TRUNC、 O_NONBLOCK     

创建文件时,指定文件访问权限。权限同时受umask影响。结论为:

文件权限 = mode & ~umask

使用头文件:<fcntl.h>

3.数据段合并和地址回填说明

open常见错误 :

1. 打开文件不存在

2. 以写方式打开只读文件(打开文件没有对应权限)

 3. 以只写方式打开目录

文件描述符:

PCB进程控制块

 可使用命令locate sched.h查看位置: /usr/src/linux-headers-3.16.0-30/include/linux/sched.h 

struct task_struct { 结构体  

文件描述符表

4.gcc编译其他参数

# gcc 编译器

## 编译过程

1. 预处理: 预处理器
    - 将 源文件,展开 头文件、替换宏(变量宏、函数宏)、替换 空行、空格、table、注释
    - gcc -E hello.c -o hello.i
        - -E: 预处理选项
        - -o:重命名。
2. 编译:编译器
    - 逐行检查程序中出现的 语法和词法 错误!简单的逻辑错误。—— **==所有编译过程中,最耗时==**
    - gcc -S hello.i -o hello.s
        - -S: 编译选项,如果编译无误,生成 .s 汇编文件。
3. 汇编:汇编器。
    - 将 .s 汇编 文件中,的所有汇编指令,翻译成二进制机器码。
    - gcc -c hello.s -o hello.o
        - -c: 汇编选项。 无错误检查。机械翻译。

4. 链接:连接器。-- ld -- 
    - 将 .o 的目标文件,链接库文件、数据段合并,地址回填。生成可执行文件。
    - gcc hello.o -o hello
        - 此过程无专用参数。 -o 不是连接过程必须使用的参数。

5.函数库简介

 本质:一组函数。具有相近的功能或操作同一数据结构。
    - <string.h> : strcpy/strcmp/strcat/strlen/strstr/strchr/strtok ....
    - 自定义库:<mysort.h> : bubble_sort / select_sort/ quick_sort / insert_sort .... 
- 作用:
    1. 代码复用。
    2. 程序积累。
- 发布形式:
    1. 源码形式:
        - 优点:方便使用者学习和使用。
        - 缺点:1. 保密性差。2. 编译程序耗时。3. 编译受平台、版本限制。
    2. 二进制形式:
        - 优点、缺点,与上述相反。

- 我们使用的函数: 标准C库:/lib/x86_64-linux-gnu/libc.so.6

6.静态库的使用


## 静态库

### 简述

- 机制:在编译程序时,复制静态库的代码片,到可执行程序中。
- 优点:将函数库中的函数本地化。寻址方便,速度快。(库函数执行效率 == 自定义函数执行效率)
- 缺点:消耗系统资源大,每个使用静态库的程序,都要复制一份,静态库。浪费内存。
- 使用场景:多用于核心程序,保证时效性,可以忽略空间。


- 静态库使用的原理

7.动态库的简介

- 机制:代码共享。

- 优点:节省内存(共享)、易于更新(动态链接)

- 缺点:相较于静态库而言,函数调用速度慢(函数地址“延时绑定”)

- 使用场景:

    1. 对程序执行速度要求不是很强烈,而对系统资源有一定要求的场景。
    2. 对应更新比较频繁程序。
        1. 停止运行程序
        2. 使用新库覆盖旧库(保证新库、旧库名称一致。接口一致。)
        3. 重启程序。

    ![1583476366325](课堂笔记03.assets/1583476366325.png)

### 重点强调

1. 动态库是否加载到内存,取决于 “程序是否运行”。
2. 动态库加载至内存的位置,不固定。

### 制作

 8.动态库制作基本流程

1. 生成与位置无关的 目标文件:

    ```shell
    gcc -fPIC -c add.c mul.c sub.c
    ```

2. 制作动态库

    ```shell
    gcc -shared -o libmymath.so add.o sub.o mul.o
    ```

3. 测试使用动态库

    ```shello
    gcc hello.c -o app -L ./lib -l mymath -I ./inc 
    ```

4. 查看动态库

    ```shell
    file libmymath.so 
    
    libmymath.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=8e82c257df06f7e69e5b0e2c30d2056f4f13422b, not stripped
    ```

5. 启动 程序 ./app ----> 报错:

    ```shell
    ./app: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory
    ```

    - 错误原因:“动态链接器” ld-linux-x86-64.so.2 搜索动态库的路径没有指定。

        - 链接器:工作于 gcc 编译4过程 中的 “链接阶段”。 工作结束,生成 可执行文件。
        - 动态链接器:工作于可执行程序运行之后,辅助加载器负责将动态库加载到内存。

    - 查看错误:**ldd** 可执行文件名

9.启动APP错误解决方案12

解决上述错误。 —— 基本思想:给 动态链接器 指定 动态库路径。

    1. 环境变量法 。

        - export LD_LIBRARY_PATH=./lib  将当前动态库所在目录,加入到环境变量中。

        - 终端一旦退出,环境变量的修改无效。

    2. 配置文件法:

        - 将上述修改环境变量的指令,写入到 ~/.bashrc 中

        - 每次启动终端,自动生效

        ![1583479995415](课堂笔记03.assets/1583479995415.png)

    

10.启动APP错误解决方案34

3. 拷贝法:

        - 受程序使用 libc 库的启发。将自定义的 libmymath.so 文件 拷贝到 /lib 或 /usr/lib 中

        - 为了执行用户自定义程序。需要修改系统配置。

    4. 【推荐使用】缓存文件法:

        1. 通过修改配置文件,修改缓存文件,生成动态连接器需要搜寻的新目录位置。

        2. 打开配置文件:sudo vim /etc/ld.so.conf   

        3. 修改配置文件:将 动态库 的绝对路径添加到  /etc/ld.so.conf 文件中。

        4. 使用 命令 sudo ldconfig -v 动态更新 ld.so.cache 文件(二进制文件)。 该文件直接影响动态连接器搜索动态库位置。

        5. 原理:

 11.makefile一组规则

# makefile

- 作用:进行项目管理。
- 初步学习:1个规则、2个函数、3个自动变量。
- 要想使用默认的make命令,管理项目。makefile文件名:必须是 “makefile”  或 “Makefile”

## makefile的规则

语法:

```makefile
目标:依赖条件
(一个tab缩进)命令

举例:
hello:hello.c
    gcc hello.c -o hello
```

- 目标的时间,必须晚于依赖条件的时间,否则,更新目标。
- 依赖条件,如果不存在,寻找新的规则去产生依赖条件。

```makefile
hello:hello.o add.o sub.o mul.o
    gcc hello.o add.o sub.o mul.o -o hello
hello.o:hello.c
    gcc -c hello.c -o hello.o
sub.o:sub.c
    gcc -c sub.c -o sub.o
add.o:add.c
    gcc -c add.c -o add.o
mul.o:mul.c
    gcc -c mul.c -o mul.o

12.makefile的两个函数

## 2个函数

```makefile
wildcard 函数:用来匹配文件名,得到字符串
src = $(wildcard ./*.c)  : 匹配当前工作目录下的所有.c文件。将文件名组成列表,赋值给变量 src
    相当于: src = add.c sub.c mul.c

patsubst 函数:用来字符串替换
obj = $(patsubst %.c, %.o, $(src)) : 将 参3 中,包含 参1的部分,替换为 参2. 
    相当于: obj = add.o sub.o mul.o
obj = $(patsubst %.c, %, $(src)) 
    相当于: obj = add sub mul
```

13.makefile自动变量的定义和使用

14.makefile的all和clean使用

### 普通变量 (自定义变量)

- 定义变量语法:变量名 = 变量值  (都是字符串)
    - 举例:foo = abc
- 取变量值语法:$(变量)
    - 举例:bar = $(foo)  ===>  bar = abc
- makefile 自带变量:
    - CC = cc
    - CPPFLAGES 
    - CFLAGES
    - LDFLAGES

### 自动变量

- $@: 在规则的命令中,表示规则中的目标。
- $^:  在规则的命令中,表示所有依赖条件。
- $<:  在规则的命令中,表示第一个依赖条件。如果将该变量应用在 “模式规则” 中,它可以将依赖条件列表中的每一个依赖,依次取出,套用模式规则。

15.模式规则和静态模式规则

模式规则

- 可以将makefile文件中,具有严格统一格式的 规则,使用模式规则代替。要求模式规则中,只能使用 “$<” 符号。

```makefile
%.o:%.c
    gcc -c $< -o $@
```

- 静态模式规则:
    - 将模式规则,指定给某一个变量使用。

```makefile
 $(obj):%.o:%.c
      gcc -c $< -o $@
```

 16.makefile的其它参数和变量使用

## 其他参数

- -n:模拟执行 makefile ,不真正执行!推荐首次编写 makefile 完成时,使用!!!
- -f:指定命名为 非 “makefile” 的文件。执行make命令

17.gbd调试、基础指令

# gdb调试器

## 要求

- 程序必须是自己编写的(能完全看懂)。
- 只能用来调试逻辑错误!
- 必须添加 -g 参数,使用 gcc 编译生成的 可以执行文件,才能调试!

## 基础指令

- -g:必须使用该参编译可执行文件,否则没有调试表!
- gdb ./a.out
- l/list:   list 1 列出源码,根据源码指定行号设置断点。 1 代表从第1行开始。
- b: b  55 在第 55 行添加 断点。  b  main   在main函数位置添加断点。  b add 、b sub... 
- run/r : 运存程序,启动调试!
    - 代码会自动运行,停止在断点处。断点对应的代码行,没有执行!
- n/next: 下一条指令(越过函数,不进入函数)
- s/step: 下一条指令(进入函数)
- p/print: 打印变量值。  如: p var ----- 查看 var 变量的值。
- continue: 继续执行断点后续的指令
- finish:结束当前函数调用。
- quit:退出当前gdb调试。

18.gbd的其他指令

- start:不使用断点,直接启动程序,开始单步调试。
- run/r:找出程序出现段错误的位置。用法:gdb启动调试,直接run 。停止的位置,就是出段错误与的代码位置。
- 设置main函数命令行参数:
    1. set args  参1 参2 参3 。。。  ( 在 start/run 之前设置。)
    2. run 参1 参2 参3 。。。
- info b : 查看断点信息表。
- b 23 if i = 5 :设置条件断点。 只有满足该条件时,断点才生效。
- 设置 断点生效、失效。
    - disable 2 :  设置编号为 2 号的断点,失效。 使用 info b 查看。
    - enable  3 :  设置编号为 3 号的断点,生效。 使用 info b 查看。

- delete 1 : 删除 编号为 1 号的断点。
- ptype : 查看变量类型。
- display:设置跟踪变量。如:display i。 跟踪i变量
- undisplay:取消跟踪变量。使用跟踪变量的编号。  如: undisplay 2 : 取消 2 号变量的跟踪。
- bt:列出当前程序,正存活着的栈帧。
- frame:根据栈帧编号,切换栈帧。

19.补充知识:栈帧

20.gbd中bt和frame命令


http://www.mrgr.cn/news/96493.html

相关文章:

  • 红宝书第二十一讲:详解JavaScript的模块化(CommonJS与ES Modules)
  • C++学习之路:指针基础
  • Windows11系统下python虚拟环境管理独家心得
  • uniapp选择文件使用formData格式提交数据
  • opencv图像处理之指纹验证
  • Java EE(18)——网络原理——应用层HTTP协议
  • leetcode 28 Find the Index of the First Occurrence in a String
  • Jmeter的压测使用
  • 从PDF到精准答案:Coze助力RAGFlow框架提升数据召回率
  • 源码刨析与插入实现:RBT比AVL强在何处?
  • SpringBoot实现RBAC权限校验模型
  • C++进阶——位图+布隆过滤器+海量数据处理
  • 小学数学解题方法专题3-列表法-提升2
  • 3.27学习总结 爬虫+二维数组+Object类常用方法
  • RocketMQ - 从消息可靠传输谈高可用
  • 在Qt中判断输入的js脚本是否只包含函数
  • fluent_UDF学习笔记
  • 横扫SQL面试——连续性登录问题
  • 在bootstrap下实现万年历
  • Muduo网络库实现 [二] - Buffer模块