linux系统编程入门

linux系统编程入门

GCC (GNU Compiler Collection GNU编译套件)

可以使用命令行控制编译器在翻译代码时应该遵循哪个c标准

安装命令:

sudo apt install gcc g++(版本大于4.8.5)

查看版本: gcc/g++ -v/—version

GCC工作流程

在这里插入图片描述
在这里插入图片描述
预处理:头文件展开 删除注释 替换宏

静态库的制作

在这里插入图片描述

静态库的使用

命令1:gcc main.c -o app -I ./include -l calc -L./lib

gcc main.c -o app 将main.c编译成为可执行文件app
-I(大写) ./include 在./include目录下搜索头文件
-l(小写) calc -L./lib 使用位于lib文件夹下的静态库

命令1 执行结果如下:
在这里插入图片描述

动态库的制作和使用

在这里插入图片描述
在这里插入图片描述
开始在lesson5文件中创建动态库,lesson6 tree结构如下:
在这里插入图片描述

接下来进入calc目录执行命令1

命令1 gcc -c -fpic add.c div.c mult.c sub.c

用于编译阶段,产生的代码没有绝对地址,全部用相对地址。执行命令1 之后lesson5中src文件内容如下:

add.c add.o div.c div.o head.h main.c mult.c mult.o sub.c sub.o

命令2: gcc -shared add.o sub.o mult.o div.o -o libcalc.so

执行命令生成动态库文件

进入library目标执行命令3: cp …/calc/libcalc.so ./lib/

可以看到libcalc.so文件被复制进了lib目录下
在这里插入图片描述
命令4: gcc main.c -o main -i include/ -L lib/ -l calc

-i(小ai)是指定头文件的搜索路径 -L是指定搜索动态库的路径 -l指定动态库名

执行命令4之后运行main程序 发现报错

在这里插入图片描述
命令5: ldd main
在这里插入图片描述
下面了解解决动态库加载失败的方法

动态库加载失败的原因


程序运行起来后就是一个进程,该进程有自己独立的内存空间,DT_RPATH段是该内存空间的地址,无法改变。

LD_LIBRARY_PATH是环境变量

解决动态库加载失败问题

1.在终端中配置环境(只在一个终端中生效)

**命令1:**env //查看环境变量
在这里插入图片描述
命令2: pwd

获取绝对路径
在这里插入图片描述
命令3: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ccb/Linux/lesson6/library/lib

修改环境变量的值 $获取原环境变量的值

注意:这里配置的环境变量是在终端中配置的,换一个终端就失效了

命令4: echo $LD_LIBRARY_PATH

查看修改后的环境变量

命令5:ldd main
在这里插入图片描述

可以看到 libcalc.so=>不再是not found了

运行程序,运行成功:
在这里插入图片描述

2. 配置用户级环境变量

首先进入home目录下,命令1:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cJSEsLAi-1667723654057)(D:\typora笔记\linux服务器开发\pics\image-20221025095129564.png)]
命令2:vim .bashrc

shift+g(跳转到文件的最后一行) o(插入一行,进入了插入模式)

插入:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ccb/Linux/lesson6/library/lib

按下esc键,从插入模式退出到命令模式,在命令模式下输入:wq保存并退出

命令3:source .bashrc

source命令也称为“点命令”,也就是一个点符号(.),是bash的内部命令。source命令通常用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录。

**命令4:**ldd main

执行命令查看动态依赖关系列表,可见libcalc.so的指向不为空
在这里插入图片描述

3.配置系统级别的环境变量

清除用户级别环境变量之后执行如下操作

命令1: sudo vim /etc/profile

shift+g(跳转到文件的最后一行) o(插入一行,进入了插入模式)

插入:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ccb/Linux/lesson6/library/lib

按下esc键,从插入模式退出到命令模式,在命令模式下输入:wq保存并退出

命令2:source .bashrc

source命令也称为“点命令”,也就是一个点符号(.),是bash的内部命令。source命令通常用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录。
在这里插入图片描述

4.修改/etc/ld.so.cache文件列表

首先删除在/etc/profile中配置的环境变量LD_LIBRARY_PATH
**命令1:**vim /etc/ld.so.cache

全是乱码,无法修改

命令2:sudo vim /etc/ld.so.conf

在ld.so.conf中插入路径名即可
在这里插入图片描述
命令3:sudo ldconfig
更新配置文件
执行main程序成功
在这里插入图片描述

静态库和动态库的对比

静态库制作过程
在这里插入图片描述
-L指定静态库路径

-l指定静态库名称

动态库制作过程
在这里插入图片描述
-fpic是生成与位置无关的目标代码。静态库链接时会把静态库代码打包到可执行程序中,代码的位置就固定了,加载到内存后位置不会发生改变。动态库加载时,不知道什么时候加载也不知道加载到内存中的哪一块区域

静态库的优缺点

在这里插入图片描述
每次更新静态库文件都要对整个程序重新进行编译

动态库的优缺点
在这里插入图片描述

Makefile

在这里插入图片描述

首先解压redis-5.0.10.tar.gz文件

tar zxvf FileName.tar.gz

进入lesson7文件内,并查看文件内容:

在这里插入图片描述
在这里插入图片描述

  • makefile中的其他规则一般都是为第一条规则服务的
makefile初体验:

进入lesson7的目录下,输入vim Makefile ,在Makefile文件中输入如下指令:

在这里插入图片描述

执行make指令,可以看到lesson7目录下多出了一个app文件,运行app文件即可
在这里插入图片描述

若生成目标之后依赖发生了变化,则目标会重新生成

若生成目标时没有依赖,则认为依赖的时间总是比目标时间早一些

第二版makefile文件

命令1:cp Makefile Makefile1

保存第一版Makefile文件到Makedile1中

命令2:vim Makefile
在这里插入图片描述
命令3:make

执行Makefile内容
在这里插入图片描述
相比与第一个版本,第二个版本在更新依赖时只需更新发生了更改的依赖,而第一个版本在更新依赖时要更新所有的依赖。

下述操作将验证上面的说法:

1.打开main.c文件进行修改(可以加个换行)

2.执行make指令,可以看到只更新了main.o依赖并重新生成了app文件
在这里插入图片描述

从自定义变量、模式匹配和函数这三个写法修改Makefile文件
Makefile中的变量

自定义变量

变量名=变量值 var=hello

◼ 预定义变量

AR : 归档维护程序的名称,默认值为 ar

CC : C 编译器的名称,默认值为 cc

CXX : C++ 编译器的名称,默认值为 g++

$@ : 目标的完整名称

$< : 第一个依赖文件的名称

$^ : 所有的依赖文件

◼ 获取变量的值

$(变量名) $(var)
在这里插入图片描述

模式匹配

%.o:%.c

  • %: 通配符,匹配一个字符串
  • 两个%匹配的是同一个字符串

%.o:%.c

​ gcc -c $< -o $@

第三版Makefile

命令1:cp Makefile Makefile2

将第二版的Makefile文件保存 到Makefile2中

命令2:vim Makefile

在Makefile中输入下图所示命令:

在这里插入图片描述

命令3:rm *.o app

删除.o文件和app

命令4:make

执行make指令,结果如下图所示:

在这里插入图片描述

将Makefile文件修改成如下内容:

在这里插入图片描述

将lesson7目录库下的.o文件和app程序删除,执行make指令重新生成app,生成之后运行app,结果如下:

在这里插入图片描述

函数

$(wildcard PATTERN…)

 功能:获取指定目录下指定类型的文件列表

 参数:PATTERN 指的是某个或多个目录下的对应的某种类型的文件,如果有多 个目录,一般使用空格间隔

 返回:得到的若干个文件的文件列表,文件名之间使用空格间隔

 示例: $(wildcard *.c ./sub/ *.c) 返回值格式: a.c b.c c.c d.c e.c f.c

$(patsubst ,, )

 功能:查找中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合 模式,如果匹配的话,则以替换。

 可以包括通配符%,表示任意长度的字串。如果 中也包含%,那么,中的这个%将是中的那个% 所代表的字串。(可以用\来转义,以\%来表示真实含义的%字符)

 返回:函数返回被替换过后的字符串

 示例: $(patsubst %.c, %.o, x.c bar.c) 返回值格式: x.o bar.o

使用wildcard和patsubst函数对Makefile文件修改,修改后的内容如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9hd4yXtH-1667723654063)(D:\typora笔记\linux服务器开发\pics\image-20221031100952028.png)]

在Makefile中添加clean规则,用于清除依赖

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0f6TLauk-1667723654063)(D:\typora笔记\linux服务器开发\pics\image-20221031101904140.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z88wK2Wz-1667723654063)(D:\typora笔记\linux服务器开发\pics\image-20221031101958726.png)]

新建一个clean文件,之后执行clean操作,clean操作并没有执行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-esj7jQdw-1667723654063)(D:\typora笔记\linux服务器开发\pics\image-20221031104014040.png)]

生成clean时没有依赖,认为依赖的时间总是比clean时间早一些,因此不会执行clean操作了

可以将clean作为一个伪目标,这样不会生成一个目标文件,不会比较目标和依赖的时间先后关系,也就可以执行clean操作了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XGqmy5bV-1667723654064)(D:\typora笔记\linux服务器开发\pics\image-20221031103851145.png)]

GDB

GDB是由GNU软件系统社区提供的调试工具,同GCC配套组成了一套完整的开发环境,GDB是Linux和许多类Unix系统中的标准开发环境。

一般来说,GDB 主要帮助你完成下面四个方面的功能:

  1. 启动程序,可以按照自定义的要求随心所欲的运行程序
  2. 可让被调试的程序在所指定的调置的断点处停住(断点可以是条件表达式)
  3. 当程序被停住时,可以检查此时程序中所发生的事
  4. 可以改变程序,将一个 BUG 产生的影响修正从而测试其他 BUG
准备工作:

通常,在为调试而编译时,我们会()关掉编译器的优化选项(-O), 并打开调 试选项(-g)。另外,-Wall在尽量不影响程序行为的情况下选项打开所有 warning,也可以发现许多问题,避免一些不必要的 BUG。

gcc -g -Wall program.c -o program

-g 选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机 器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证 gdb 能找到源文件

为验证以上理论,先加入-g指令生成含有源代码的可执行文件test,再生成不含有源代码信息的可执行程序test1,比较两个程序的大小,发现test确实比test1大一些,test文件比test1文件多了源代码信息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OiVl5dbe-1667723654064)(D:\typora笔记\linux服务器开发\pics\image-20221031144353323.png)]

gdb命令:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vq08W7vP-1667723654064)(D:\typora笔记\linux服务器开发\pics\image-20221031110956390.png)]

输入gdb test命令进入gdb模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PEAzHKgV-1667723654064)(D:\typora笔记\linux服务器开发\pics\image-20221031144830619.png)]

在gdb中给程序设置参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PgWmpjvp-1667723654065)(D:\typora笔记\linux服务器开发\pics\image-20221031145144054.png)]

可以使用vim查看代码(使用vim查看代码时 通过命令 :set nu可以显示代码行号),也可以使用gdb命令查看代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gI11QGla-1667723654065)(D:\typora笔记\linux服务器开发\pics\image-20221031145947920.png)]

使用gdb调试时(使用ctrl+l清空命令窗口),源代码文件(不能改名字)和可执行程序要在一起

输入一个list显示10行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AJBHYjsf-1667723654065)(D:\typora笔记\linux服务器开发\pics\image-20221031151518509.png)]

给list加入参数 比如函数名或者代码行数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ez1plsVX-1667723654065)(D:\typora笔记\linux服务器开发\pics\image-20221031151731130.png)]

使用gcc编译.cpp文件会报错

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y1kSDYvL-1667723654066)(D:\typora笔记\linux服务器开发\pics\image-20221031152110077.png)]

应使用g++编译.cpp文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NSI4fuGF-1667723654066)(D:\typora笔记\linux服务器开发\pics\image-20221031152250336.png)]

使用gdb打开main

查看非当前文件代码,如查看bubble.cpp中的代码:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UNqYjgsR-1667723654066)(D:\typora笔记\linux服务器开发\pics\image-20221031152731015.png)]

修改list指令显示的代码行数:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8cjBdiIS-1667723654066)(D:\typora笔记\linux服务器开发\pics\image-20221031153116503.png)]

断点操作:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hU5h8pdt-1667723654067)(D:\typora笔记\linux服务器开发\pics\image-20221031111017143.png)]

添加断点:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WBNxCKWu-1667723654067)(D:\typora笔记\linux服务器开发\pics\image-20221031162117061.png)]

删除断点:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BQ7S1GuB-1667723654067)(D:\typora笔记\linux服务器开发\pics\image-20221031162353443.png)]

设置断点无效:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mR8bCkk1-1667723654067)(D:\typora笔记\linux服务器开发\pics\image-20221031162712456.png)]

设置条件断点:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZsNzaOZH-1667723654068)(D:\typora笔记\linux服务器开发\pics\image-20221031162932061.png)]

调试命令

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bt9TNoZx-1667723654068)(D:\typora笔记\linux服务器开发\pics\image-20221031111038421.png)]

进入Linux lesson8目录下,输入start指令,程序停在int main()这一行

输入c之后运行全部程序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lDTjXjPJ-1667723654068)(D:\typora笔记\linux服务器开发\pics\image-20221101123901432.png)]

退出调试main程序,调试test,并给添加三个断点:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KC7BN4ft-1667723654068)(D:\typora笔记\linux服务器开发\pics\image-20221101130655287.png)]

输入run指令,程序开始运行:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fhvDOWQg-1667723654069)(D:\typora笔记\linux服务器开发\pics\image-20221101130902433.png)]

我们想要查看变量a和变量b的值,可以使用print指令打印a和b的值,但是每次查看都要输入两次print指令,有些麻烦。可以使用自动变量操作,每次运行之后自动打印a和b的值:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eAqcJXg0-1667723654069)(D:\typora笔记\linux服务器开发\pics\image-20221101131154013.png)]

查看已存在的display情况(info display)&删除自动变量(undisplay number):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0KAmJifF-1667723654069)(D:\typora笔记\linux服务器开发\pics\image-20221101131550648.png)]

文件IO

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7EyoHyF4-1667723654069)(D:\typora笔记\linux服务器开发\pics\image-20221101190037589.png)]

fopen打开一个文件之后会返回一个FILE类型的指针,该指针指向一个结构体。结构体中含有文件描述符/文件句柄(整型值)、文件读写指针位置和I/O缓冲区(内存地址)。

什么情况下数据会从内存刷新到磁盘:

  • 缓冲区满了才会讲缓冲区内容写入磁盘(会导致文件写入的实时性不高)
  • 调用fflush指令刷新缓冲区
  • 正常关闭文件

标准c库fopen指令比linux打开文件的指令效率更高,因为有缓存区的存在。但正是缓冲区的存在导致了文件写入实时性不高,因此在网络编程中一般使用linux的写入指令。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rXrKm038-1667723654070)(D:\typora笔记\linux服务器开发\pics\image-20221101192114842.png)]

虚拟地址空间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5eoE3CTA-1667723654070)(C:\Users\17413\AppData\Roaming\Typora\typora-user-images\image-202211021012176946.png)]

堆空间是从低地址往高地址存,栈空间是从高地址往低地址存。

主存和内存的定义

需要明确主存是指存放当前正要执行或者刚执行完毕的程序和数据的存储器是主存储器

存放正在执行的程序或正在使用的数据是cache,cache解决了CPU与主存速度匹配的问题。

一般将主存和cache统称为内存

虚拟地址空间解决的是主存容量和价格的矛盾,使速度接近主存而价格接近外存。

编译器中的变量地址是逻辑地址,MMU会将逻辑地址映射为物理地址(主存储器上是实际地址)

cpu
高速缓冲存储器Cache
主存MM
外存
内存管理单元MMU
操作系统

文件描述符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MLJBscfe-1667723654070)(D:\typora笔记\linux服务器开发\pics\image-20221102113330837.png)]

文件描述符表是一个数组,大小默认是1024,前三个被占用(标准输入 标准输出 标准错误)。

Linux系统IO函数

  1. int open(const char *pathname, int flags);
  2. int open(const char *pathname, int flags, mode_t mode);
  3. int close(int fd);
  4. ssize_t read(int fd, void *buf, size_t count);
  5. ssize_t write(int fd, const void *buf, size_t count);
  6. off_t lseek(int fd, off_t offset, int whence);
  7. int stat(const char *pathname, struct stat *statbuf);
  8. int lstat(const char *pathname, struct stat *statbuf);

在lesson9目录下,open.c使用函数1,create.c使用函数2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q3M9Yq9e-1667723654070)(D:\typora笔记\linux服务器开发\pics\image-20221104154557086.png)]

int open(const char *pathname, int flags, mode_t mode);//可变参数

​ 参数:

flags:对文件操作权限的设置和其他设置。flags参数是一个int类型的数据,占4个字节,32位

​ flags 32个位 每一位都是一个标志位

​ - 必选项:O_RDONLY, O_WRONLY, or O_RDWR. 三个操作互斥

​ These request opening the file read-only, write-only,or read/write

​ - 可选项:O_CREAT 文件不存在,创建新文件

mode:八进制的数,表示用户对新创建文件的操作权限,比如:0775

​ 最终的权限是:mode & ~umaskumask的作用是抹去某些权限

​ 返回值:

​ open(), openat(), and creat() return the new file descriptor,or -1 if an error occurred

create.c中的代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include<unistd.h>

int main(){
    //创建一个新的文件
    int fd= open("create.txt",O_RDWR | O_CREAT,0777);
    if(fd==-1){
        perror("open");
    }
    //关闭
    close(fd);
    return 0;
}

需要注意的是函数2中的mode是一个八进制数,该数表示用户对新创建文件的操作权限,比如:0775,但最终的权限是由mode & ~umask决定的,umask的作用是抹去某些权限。在create.c的代码中,我们设置了mode是0777,但是对create.c编译运行之后产生的create.txt文件的操作权限如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QfAELVyG-1667723654071)(D:\typora笔记\linux服务器开发\pics\image-20221104160602519.png)]

​ 返回值:

​ open(), openat(), and creat() return the new file descriptor,or -1 if an error occurred

create.c中的代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include<unistd.h>

int main(){
    //创建一个新的文件
    int fd= open("create.txt",O_RDWR | O_CREAT,0777);
    if(fd==-1){
        perror("open");
    }
    //关闭
    close(fd);
    return 0;
}

需要注意的是函数2中的mode是一个八进制数,该数表示用户对新创建文件的操作权限,比如:0775,但最终的权限是由mode & ~umask决定的,umask的作用是抹去某些权限。在create.c的代码中,我们设置了mode是0777,但是对create.c编译运行之后产生的create.txt文件的操作权限如下:

[外链图片转存中…(img-QfAELVyG-1667723654071)]

操作权限为:rwx rwx r-x(111 111 101,即775),我们设置的mode为0777,但是实际文件的操作权限为0775,可见实际操作权限并不仅仅由我们设置的mode决定。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值