18. Linux API 编程预备知识


【操作系统基础程序】

操作系统提供了一组用户使用计算机所需的基础程序,实现了使用计算机必备的基础功能,比如:用户管理、外存储器管理、文件管理、设置网络连接、编译程序,这组程序所在目录会记录在环境变量中,直接在终端指定其名称即可使用。

多数基础程序执行时需要传入参数,参数赋值有固定规则,若参数用于启动或设置一种功能,则需要前缀-符号。

shutdown -h 0    //shutdown程序用于关机或重启,-h参数表示关机,0为设置的关机倒计时。
gcc -masm=intel  //gcc用于编译代码,-masm参数表示设置汇编语言语法类型,此参数需要使用=符号直接赋值具体类型。

另外多个参数功能不冲突时可以同时指定,此时只需编写一个-符号即可。

tar -czvf ali.tar.gz a.c b.c    //tar用于文件压缩与打包,czvf分别设置一种功能,这里一共设置4种功能,ali.tar.gz为打包文件的名称,a.c和b.c为需要打包的文件。

有些参数不需要使用-符号。

cd ~/data    //cd设置终端工作目录,之后直接编写路径名称即可。


鉴于介绍linux操作系统常用命令的书籍非常多,这里不再重复。


【操作系统API】

API,中文名为应用程序编程接口,是操作系统提供的一组C语言函数库,存放在/usr/include/目录中,提供了程序频繁使用的功能,其中很多功能是通过glibc调用系统调用实现的。

在计算机操作系统发展早期,各种操作系统的API使用方式都有区别,频繁学习不同的API非常耗费精力,为此人们制定了统一的API使用规则,称为POSIX(可移植操作系统接口),它规定了API需要提供哪些功能、每种功能对应函数和全局变量的使用方式,开源操作系统的API基本上都遵循此规则。

掩码

有些API函数需要使用一个数据指定启用哪些功能、不启用哪些功能,此数据称为掩码,掩码使用二进制位记录每个功能是否生效,一般值为1表示生效、值为0不生效,有些功能使用多个二进制位的组合指定是否生效,多个掩码指定的生效功能可以使用按位或运算进行整合。

API函数执行结果

API函数使用返回值告知调用者执行结果,多数情况下执行成功返回0或大于0的整数,执行失败返回-1,若返回值为指针,则返回0表示执行出错。

若执行出错后需判断具体原因,可以使用errno.h文件,此文件内有一个全局变量errno,其存储了API函数执行结果的具体原因,每一种执行结果使用一个数值表示,每个数值表示的信息我们不方便直接观察,可以使用perror函数输出执行结果原因,perror函数会自动读取errno的值并判断执行结果类型。

注:
1.perror的执行依赖stdio.h。
2.errno会随下次执行API函数而被修改。

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
int main()
{int result = open("/home/ali/a.txt", O_RDWR | O_APPEND);    //打开文件if(result > -1){printf("打开文件成功,文件描述符编号:%d\n", result);}else{perror("open函数执行失败,原因");    //参数为首先输出的字符串,之后输出errno含义}return 0;
}


【GCC编译器】

GCC是GNU项目中编译器子项目的名称,主要用于编译C语言和C++语言代码,编译C语言代码时使用gcc程序,编译C++语言代码时使用g++程序。

将源代码制作为一个ELF文件需要经过三个步骤:编译、汇编、连接,三个步骤分别使用以下三种工具完成:
1.编译器,将高级语言代码转换为对应的汇编语言代码。
2.汇编器,将汇编语言代码转换为对应的指令数据、数学数据。
3.连接器,将编译后的文件添加必要的节组成ELF文件。

gcc是编译器,只有编译功能,没有汇编与连接功能,但是因为编译与汇编、连接通常需要一起使用,所以在使用gcc编译代码时默认会自动调用汇编器、连接器制作为ELF文件。

gcc /home/ali/a.c    //参数指定源代码文件,可以使用相对路径、绝对路径
gcc a.c b.c          //若程序代码在多个文件内,需要同时指定所有的文件路径

预处理

编译器的预处理功能用于对源代码中预处理指令进行解释,主要有以下两种行为:
1.将 #include 连接的文件内容复制到本文件中。
2.将使用 #define 定义的宏代码转换为具体的代码。

GCC操作文件的类型

gcc通过文件后缀名确定文件类型,常用后缀如下:

c,c语言代码文件
cc,c++语言代码文件
cpp,c++语言代码文件
s,汇编语言代码文件
o,目标文件
a,静态连接库文件
so,动态连接库文件

常用参数

-o,小写字母o,指定编译后的文件名称,示例:gcc a.c -o ali.out,a.c为源代码文件路径,ali.out为编译后的文件路径,这里全部使用相对路径。
-O,大写字符O,设置编译优化级别,有4种级别,使用编号0-3表示,0表示不优化,3表示最高优化,默认为0级优化,级别值紧邻参数之后,示例:gcc -O2 a.c。
------------------
-E,只进行预处理,不编译代码。
-S,只进行预处理、编译,不进行汇编、连接。
-c,只进行预处理、编译、汇编,不进行连接,用于制作目标文件。
-fPIC,与-c组合使用,用于制作动态连接库使用的目标文件。
------------------
-shared,将目标文件打包并制作为动态连接库。
-static,调用连接库时使用静态库版本,而非动态库,编译后的程序体积会大很多。
-share,调用连接库时尽量使用动态库版本,生成的文件体积更小。
------------------
-g,添加调试功能相关数据,方便使用调试器调试程序,若不添加此参数则使用调试器调试程序时某些功能不可用,同时注意调试程序时不应该使用-O参数开启优化。
-s,编译后的程序不保存源代码中的数据名。
------------------
-masm,指定汇编代码的语法类型,比如在高级语言中内嵌汇编代码、或使用-S参数只编译代码时,都可以使用此参数,默认使用AT&T语法,若使用英特尔语法则应该添加参数 -masm=intel。
-std,设置C语言、C++语言的版本,比如:c89、c99、c11、c17、c++98、c++03、c++11、c++14、c++17,具体的版本值使用=符号赋值,示例:-std=c99,-std=c++03。
------------------
-Wall,生成所有警告和错误信息(数组越界访问除外),若不指定此参数则只显示必要的警告信息,比如设置了返回值的函数没有为返回值赋值,此时不使用此参数不会有警告。
-fpermissive,将不符合语法规则的某些代码改为可以编译,但是会生成警告信息,比如C++代码中变量指针存储一个常量数据的地址,默认禁止编译,添加此参数即可编译,注意并非针对所有错误代码,有些错误不可忽略。
-fsanitize=address,检查源代码中各种内存错误访问相关信息,原理是在代码中添加各种检查代码,若出错则会在终端输出错误信息,并自动终止程序,一般用于调试程序。
------------------
-v,查看gcc相关属性信息,包括gcc版本号。


【gdb调试器】

编写代码时经常会因为各种原因遇到意想不到的错误,比如:思维不严谨、对某个API函数运行方式不完全了解、对某个功能的运行原理不完全了解,代码错误是不可避免的,使用调试器可以观察程序的各种执行错误,调试器主要功能如下:
1.设置程序断点,程序执行到此处时会暂停。
2.程序单步执行,程序每执行一条指令就暂停。
3.查询程序执行时某些变量的值。
4.程序执行时临时修改某些变量的值。

使用方式

首先在终端执行gdb程序,参数设置为要调试程序的路径,动gdb后输入控制命令启动不同的功能,常用控制命令如下:

set args,设置被调试程序的main函数参数,示例:set args ali xyy,这里传入了2个参数,分别是ali和xyy。
list,显示程序源代码,示例:list 1,从第一行开始显示源代码,默认每次显示10行,之后按enter键显示下10行,示例:list main,显示main函数的源代码。
------------------
break/b,添加一个断点,可以使用代码行数或函数名指定断点添加处,程序执行到断点处会暂停,示例:break 9,在第9行添加一个断点。
info break/b,查询所有断点。
delete/d,取消一个断点,通过断点编号指定,示例:delete 1,取消编号为1的断点,示例:delete 1-5,取消编号1到5的断点。
disable,禁用指定编号的断点,示例:disable 1。
enable,启用指定编号的断点,示例:enable 1。
------------------
run/r,执行程序开始调试。
continue/c,在断点处恢复执行。
next/n,程序暂停后,单步执行下一条指令,若遇到跳转函数指令则忽略,执行之后的指令。
step/s,程序暂停后,单步执行下一条指令,若遇到跳转函数指令则进入函数,若跳转的函数是动态库函数则会产生错误。
finish/fin,程序暂停后,执行到下一个断点处,若本函数没有断点则执行到本函数末尾,并返回到上一级函数暂停。
until,跳转到源代码指定行数执行。
------------------
display,设置一个跟踪变量,每次暂停后自动查询此变量的值并输出,示例:display a,自动跟踪变量a。
undisplay,取消一个跟踪变量,需要使用跟踪变量编号指定,而不是变量名,示例:undisplay 1,取消编号为1的跟踪变量。
print/p,手动查询指定变量的值,示例:print a,查询变量a的值。
info locals,查询所有局部变量的值。
info reg,查询所有寄存器的值。
set var,修改指定变量的值,示例:set var a=0。
------------------
backtrace/bt,查询本函数调用者的执行顺序,也就是向前查询都有哪些函数执行。
call,跳转到指定函数执行一次并返回,同时输出此函数的返回值,示例:call ali(),跳转到ali函数执行,若有参数则需要同时为参数赋值。
disass,反汇编指定函数,示例:disass ali,反汇编ali函数。
------------------
quit/q,退出gdb。

注:有些参数可以使用简写,比如break可以简写为b。


【make】

大型项目会有几十甚至上万个源代码文件,如果每个源代码文件都需要手动编译的话会非常麻烦,这时候就需要使用make自动执行一些命令,make执行的操作使用make脚本文件说明,脚本文件默认名为makefile或Makefile。

make常用参数如下:

-f,指定make脚本文件的路径,若不指定则在工作目录中查找makefile文件。
-n,输出需要执行的操作,但是不真正的执行这些操作,用于检查makefile文件。
-j,指定使用CPU的几个核心进行工作,示例:make -j 4,使用4个核心。
-k,出现错误后继续执行,而非停止。


makefile脚本文件代码的基础编写规则如下。

注释

使用#符号设置一行注释。

# 这里是单行注释

创建行为

action1 : a.c b.c c.cgcc -c a.c -o a.ogcc -c b.c -o b.ogcc -c c.c -o c.o

第一行用于设置行为名称以及此行为需要使用的文件和其它行为,action1为行为名,:符号之后编写此行为需要使用的文件(可省略)以及调用的其它行为(不可省略),这里指定了3个源代码文件。
行为名之后的行编写此行为执行的命令,每行命令开头需要使用tab键输入一个制表符。

使用 @ 符号

默认情况下make会在终端输出执行了哪些命令,在命令前添加@符号则不输出。

action1 : a.c b.c c.c@ gcc -c a.c -o a.o@ gcc -c b.c -o b.o@ gcc -c c.c -o c.o

使用 - 符号

默认情况下遇到无法执行的命令make会终止执行,剩余命令都不会执行,在命令前添加-符号表示若此命令执行出错则忽略,继续执行之后的命令。

action1 : a.c b.c c.c@- gcc -c a.c -o a.o@ gcc -c b.c -o b.o@ gcc -c c.c -o c.o

使用多个行为

需要执行的命令很多时,往往需要将命令分到不同的行为中,make默认从第一个行为开始执行,并且只执行第一个行为,其他行为需要被调用才能执行,并且被调用的行为会首先执行,就像C语言中的其它函数必须直接或间接的被main函数调用才能执行一样。

# 制作可执行程序
action1 : action2 a.o b.o c.ogcc a.o b.o c.o -o ali.out# 编译目标文件
action2 : a.c b.c c.cgcc -c a.c -o a.ogcc -c b.c -o b.ogcc -c c.c -o c.o# 清理工作
clean : rm -f a.o b.o c.o    # rm命令用于删除文件

make从action1行为开始执行,此行为又调用了action2行为,action2会首先执行,之后再执行action1,最后的clean行为不会自动执行,只能在终端执行make时手动调用此行为执行,示例:make clean

使用字符串变量

定义行为时可以使用字符串指定行为属性,行为名称、行为使用文件、行为执行命令都可以使用字符串指定。

# 定义字符串
s1 = a.c b.c c.c
s2 = gcc -c a.c -o a.o
s3 = gcc -c b.c -o b.o
s4 = gcc -c c.c -o c.o
s5 = a.o b.o c.o -o ali.out# 定义行为
action1 : ${s1}    # 使用 ${字符串名} 或 $(字符串名) 调用字符串${s2}${s3}${s4}gcc ${s5}

字符串赋值运算符

=运算符,直接赋值,多次使用=赋值时以最后一次赋值为准。
:=运算符,引用另一个字符串现在的值进行赋值。
?=运算符,有条件赋值,若变量没有赋值则进行赋值,若变量已经赋值则不进行赋值。
+=运算符,增加字符串中的字符,新增字符与原有字符使用空格分隔,常用于为执行命令添加参数。

# 定义字符串
${s1}         # 定义不赋值的字符串
${s2}
s1 += a.c
s1 += b.c
s1 += c.c
s2 ?= gcc ${s1}# 定义行为
action1 : ${s1}${s2}

嵌套调用字符串

s1 = gcc a.c b.c c.c -o ali.out
s2 = 1
s3 = ${s${s2}}   # 此行将被解释为 s3 = s1action1 :${s3}

条件语句

s1 = a.c 
${s2}ifeq (${s1}, "a.c")    # 若s1等于a.c则执行ifeq语句内脚本代码,否则执行else语句内脚本代码,注意ifeq之后需要有空格
s2 = b.c
else
s2 = a.c
endif                  # 条件语句末尾

函数

make内置了一组函数,用于实现脚本代码常用功能,脚本代码可以调用这些函数执行,调用方式:$(函数名 参数),其中()也可写为{}。

使用 wildcard 函数查询文件名

$(wildcard 参数)

参数为要查询的文件名,可以使用通配符,查询到的多个符合条件文件的名称会组合在一起形成一个字符串,中间使用空格隔开,并返回此字符串。
 

s1 = $(wildcard *.o)      # 查询工作目录所有后缀.o的文件
s2 = $(wildcard ~/*.c)    # 查询用户主目录所有后缀.c的文件action1 :@ echo ${s1}       # echo命令用于在终端输出指定字符@ echo ${s2}

使用 patsubst 函数修改字符串

$(patsubst 参数1, 参数2, 参数3)

参数1,指定需要修改的部分
参数2,指定修改后的值
参数3,提供需要修改的字符串

s1 = a.c b.c c.c
s2 = $(patsubst %c, %o, ${s1})    # 将s1中的c改为o,s2 = a.o b.o c.oaction1 :@ echo ${s2}

使用 foreach 函数循环处理字符串

此函数用于循环分割并修改一个字符串,首先根据字符串内空格将字符串分割为多份,之后对每份进行处理(比如添加字符),最后将处理后的字符串重新组合并返回。

$(foreach 参数1, 参数2, 参数3)

参数1,临时存储每次循环所用变量。
参数2,需要处理的字符串。
参数3,每次循环对字符串的操作。

s1 = a b c
${s2}
s3 = $(foreach s2, ${s1}, ${s2}.o)    # s3 = a.o b.o c.oaction1 :@ echo ${s3}

上述代码中,foreach会遍历字符串s1,每次循环以空格作为分割符取其中一段,之后将其临时存储到s2中,之后为此段内容添加.o,循环处理完s1的所有分段后,将处理后的分段组合为一个字符串并返回。

使用 dir 函数读取目录

s1 = $(dir)*.c       # 查询工作目录中所有后缀.c的文件
s2 = $(dir ~/)*.c    # 查询指定目录中所有后缀.c的文件,目录名必须以/符号结尾action1 :@ echo ${s1}@ echo ${s2}

进入子目录执行 make

action1 :make -C data    # 进入名为data的子目录继续执行make,执行完毕后返回


同时还可以向子目录内的makefile脚本文件传递一个字符串变量。

export s1 = ali     # 使用export命令设置传递的变量
action1 :make -C data    # data目录中的makefile脚本文件可以直接使用s1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/815623.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java项目实战之图书管理系统(1)

✅作者简介&#xff1a;大家好&#xff0c;我是再无B&#xff5e;U&#xff5e;G&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 1.背景 图书管理系统是一种用于管理图书…

基于springboot的网上订餐管理系统

前言 本次毕业设计的题目就是基于Java的网上订餐管理系统。本论文就毕业设计的容&#xff0c;系统地阐述了整个基于Java的网上订餐管理系统的功能与实现。实现了从菜品管理&#xff0c;菜品分类和查询&#xff0c;到订餐车实现&#xff0c;用户订单处理&#xff0c;再到系统管…

ERROR 1052 (23000): Column ‘deptno‘ in field list is ambiguous

错误原因&#xff1a; 这个错误通常是在多表查询中&#xff0c;因为你的SQL查询中包含了多个表&#xff0c;并且这些表中都有一个名为deptno的列。这会导致数据库无法确定你要引用哪个表中的 deptno列&#xff0c;从而产生歧义。 解决方法&#xff1a; 为了解决这个问…

JVM虚拟机(三)垃圾回收简介、垃圾回收算法、分代回收、垃圾回收器种类、G1垃圾回收器

目录 一、什么是垃圾回收&#xff1f;1.1 什么是垃圾回收&#xff1f;1.2 什么对象能被垃圾回收&#xff1f;1&#xff09;引用计数法2&#xff09;可达性分析算法 二、JVM 垃圾回收算法2.1 标记清除算法2.2 标记整理算法&#xff08;标记压缩算法&#xff09;2.3 复制算法2.4 …

python基于opencv实现数籽粒

千粒重是一个重要的农艺性状&#xff0c;通过对其的测量和研究&#xff0c;我们可以更好地理解作物的生长状况&#xff0c;优化农业生产&#xff0c;提高作物产量和品质。但数籽粒数目是一个很繁琐和痛苦的过程&#xff0c;我们现在用一个简单的python程序来数水稻籽粒。代码的…

鸿蒙语言TypeScript学习第16天:【类】

1、TypeScript 类 TypeScript 是面向对象的 JavaScript。 类描述了所创建的对象共同的属性和方法。 TypeScript 支持面向对象的所有特性&#xff0c;比如 类、接口等。 TypeScript 类定义方式如下&#xff1a; class class_name { // 类作用域 }定义类的关键字为 class&am…

Collection接口和List接口作用和解析

在 Java 中&#xff0c;Collection接口和List接口都是处理集合数据的重要接口。 Collection接口是所有集合类的父接口&#xff0c;它定义了一些基本的集合操作方法&#xff0c;例如&#xff1a; 添加元素&#xff1a;add(E e)移除元素&#xff1a;remove(Object o)清空集合&a…

专业照片编辑软件ON1 Photo RAW 2024 mac/win

ON1 Photo RAW 2024 for Mac是一款集专业性与易用性于一体的照片编辑软件。它拥有简洁直观的用户界面&#xff0c;即便对于摄影新手&#xff0c;也能快速上手。软件支持RAW格式照片处理&#xff0c;能够完整保留照片原始信息&#xff0c;让后期调整更加灵活。 在功能方面&#…

boost之bimaps

Boost.Bimap 是 Boost 库中的一个容器&#xff0c;它支持双向映射&#xff0c;即允许通过键查找值&#xff0c;也允许通过值查找键。 Boost.Bimap 的主要功能介绍如下&#xff1a; 双向查找&#xff1a;与 STL 中的 map 和 multimap 不同&#xff0c;这两者只能进行单向映射&a…

基于LabVIEW的CAN通信系统开发案例

基于LabVIEW的CAN通信系统开发案例 介绍了基于LabVIEW开发的CAN通信系统&#xff0c;该系统主要用于汽车行业的数据监控与分析。通过对CAN通信协议的有效应用&#xff0c;实现了车辆控制系统的高效信息交换与实时数据处理&#xff0c;从而提升了车辆性能的检测与优化能力。 项…

点击按钮(文字)调起elementUI大图预览

时隔一年&#xff0c;我又回来了 ~ 最近在做后台&#xff0c;遇到一个需求&#xff0c;就是点击“查看详情”按钮&#xff0c;调起elementUI的大图预览功能&#xff0c;预览多张图片&#xff0c;如下图&#xff1a; 首先想到的是使用element-ui的el-image组件&#xff0c;但它是…

Elasticsearch中父子文档的关联:利用Join类型赋予文档的层级关系

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! Elasticsearch是一个强大的搜索引擎&#xff0c;它提供了丰富的功能来满足复杂的搜索需求。其中&#xff0c;父子索引类型的join功…

蓝桥杯之注意事项

1.特殊求解的地方 2.一些数学公式 比如二叉树求全深度数值那道题 3.掌握有关库函数 #include<algorithm> 包含sort&#xff08;&#xff09;函数【排列函数】C sort()排序详解-CSDN博客&#xff0c;next_permutation()函数【求解全排列问题】求解数组大小sizeof(arr…

Qt自定义标题栏【即取即用模板】

头文件 #ifndef TITLEWDG_H #define TITLEWDG_H#include <QWidget>namespace Ui { class TitleWdg; }class TitleWdg : public QWidget {Q_OBJECTpublic:explicit TitleWdg(QWidget *parent nullptr);~TitleWdg(); signals:void maximize();void minimize();void cl…

商业银行风险管理

商业银行风险管理 银行业风险类型概述管理信用风险管理利率风险缺口分析 持续期分析利率互换消除利率风险表外业务的风险管理 银行业风险类型概述 信用风险市场风险&#xff08;利率风险、汇率风险等市场价 格风险&#xff09;财务风险&#xff08;流动性风险&#xff09;操作…

【Java EE】 IoC详解(Bean的存储)

文章目录 &#x1f38d;Controller&#xff08;控制器存储&#xff09;&#x1f338;如何从Spring容器中获取对象&#xff08;ApplicationContext&#xff09;&#x1f338;获取bean对象的其他方式&#xff08;BeanFactory&#xff09;&#x1f338;Bean 命名约定&#x1f338;…

判断密码c++

题目描述 某平台对新用户注册密码做如下限制: ①长度是8到16位&#xff0c;如果不符会给出提示“password should be 8 to 16 long" ②逐一判断密码字符&#xff0c;如果是纯数字就给出提示“password should not be entirely numeric”&#xff0c;如果密码符合以上要…

支持向量机模型

通过5个条件判定一件事情是否会发生&#xff0c;5个条件对这件事情是否发生的影响力不同&#xff0c;计算每个条件对这件事情发生的影响力多大&#xff0c;写一个支持向量机模型程序,最后打印5个条件分别的影响力。 示例一 为了计算每个条件对一件事情发生的影响力&#xff0c…

Linux nfs挂载失败处理

mount.nfs: access denied by server while mounting 192.168.0.1:/home/test 其中一种可能原因是文件目录没有nfs权限&#xff0c;可以编辑/etc/exports文件添加权限后重试&#xff1a; /home/xxx *(insecure,rw,sync,no_root_squash,no_all_squash,no_subtree_check) 参考资…

6-测试内存告警

在 CentOS 8 中&#xff0c;如果你无法直接找到 epel-release 包或是遇到其他仓库配置问题&#xff0c;你可能需要使用其他方式添加EPEL仓库。由于 CentOS 8 已经达到了其生命周期的结束&#xff0c;官方仓库和EPEL仓库的管理可能会有所不同。这里有一种方法可以手动添加EPEL仓…