天天动画片 > 八卦谈 > Linux基础(一)——系统编程入门

Linux基础(一)——系统编程入门

八卦谈 佚名 2024-03-10 02:25:55

一、GCC

GCC是GNU编译器集合(GNU Compiler Collection)的缩写。它是由GNU开发的一款自由软件编译器,能够编译多种编程语言,包括C、C++、Objective-C、Fortran、Ada和其他语言。GCC拥有多种编译选项和优化选项,可用于生成多种平台和多种体系结构下的可执行程序或库文件。

GCC作为一个编译器集合,包括了多个编译器和工具链,如GCC C 编译器(gcc)、GCC C++ 编译器(g++)、GCC Objective-C 编译器(objc)等等。此外,GCC还提供了一些工具,用于代码分析、调试、优化等,例如GCC Profiler、GCC Debugger等。

GCC是自由软件,可以在各种操作系统上使用,包括Linux、Unix、Mac OS X和Windows等。它的灵活性和可移植性使得它成为许多开源项目的首选编译器。
1. 预处理:在这一步中,GCC会解析源代码,处理所有的预处理指令,例如#include、#define等。预处理器会把源代码转换为一组标记(token)序列,这些标记序列将成为后续编译阶段的输入。

2. 编译:在这一步中,GCC会把预处理后的源代码翻译成汇编语言,生成相应的汇编代码文件。这个阶段的主要任务是将高级语言转换成底层语言,例如机器指令。

3. 汇编:在这一步中,GCC会把汇编代码转换成机器指令,并生成目标文件。目标文件是一种包含机器指令的二进制文件,可以被链接器使用。

4. 链接:在这一步中,GCC会把目标文件和库文件链接起来,生成可执行文件。链接器会把程序需要的各个模块组合起来,解决符号引用问题,生成最终的可执行文件。
GCC和G++是GNU Compiler Collection(GNU编译器集合)中的两个编译器,其中GCC是通用编译器,可以编译多种编程语言,包括C、C++、Objective-C、Fortran、Ada和其他语言,而G++是GCC的C++编译器。

虽然GCC和G++都可以编译C++代码,但它们之间有一些细微的区别。下面列出了一些主要的区别:

1. 默认语言模式不同:GCC默认编译C语言,而G++默认编译C++语言。

2. 链接器不同:GCC使用GNU链接器(GNU Linker),而G++使用GNU链接器和C++运行时库。

3. 标准库链接不同:GCC编译器默认链接C标准库,而G++编译器默认链接C++标准库。

4. 编译选项不同:G++编译器默认使用C++编译选项,如-fno-implicit-templates,而GCC则不会。

总而言之,GCC和G++之间的主要区别在于它们默认使用的语言模式、链接器和标准库等方面。但是,这些区别并不是绝对的,因为GCC和G++都具有高度的灵活性,可以通过编译选项进行自定义。

二、静态库的制作与使用

静态库和动态库都是在编译时链接到程序中以提供所需功能的库文件,它们的主要区别在于其加载方式和使用方式。

静态库是在编译时直接将库代码嵌入到可执行文件中,因此在运行时不需要额外的加载操作。这意味着静态库会增加可执行文件的大小,但也保证了程序的独立性和稳定性。每次程序运行时都会使用相同版本的库代码,这可以避免由于库更新而导致程序出现错误或崩溃的情况。

动态库则是在程序运行时才被加载到内存中,并且多个程序可以共享一个动态库的实例。这意味着可以节省内存空间,并且通过动态库的更新可以使得多个程序同时受益。但是,由于动态库的加载需要时间,因此可能会对程序的启动速度产生一定影响。

总之,静态库适用于需要独立性和稳定性的场景,而动态库适用于需要共享和更新的场景。
1. 编译目标文件:首先需要将需要打包成静态库的源文件编译成目标文件。可以使用编译器(如GCC)将.c或.cpp文件编译成.o目标文件,或者使用汇编器将.asm文件编译成.o目标文件。

2. 打包目标文件:将所有编译好的目标文件打包成一个归档文件(archive file),通常使用ar命令进行打包,例如:`ar rcs libname.a file1.o file2.o`。其中,libname.a为静态库名称,file1.o和file2.o为需要打包的目标文件。

3. 安装静态库:将静态库安装到系统目录中,以便其他程序可以使用。可以使用命令`sudo cp libname.a /usr/lib/`将静态库复制到系统库目录中,或者使用`sudo make install`将静态库安装到系统库目录中。

4. 使用静态库:在需要使用静态库的程序中,可以使用编译器链接静态库,使得程序可以调用库中的函数和变量。使用方法如下:`gcc -o myprogram myprogram.c -L/path/to/lib -lname`,其中,L选项指定静态库所在路径,lname选项指定静态库名称。

三、动态库的制作与使用

1. 编译目标文件:和静态库一样,需要将需要打包成动态库的源文件编译成目标文件。可以使用编译器(如GCC)将.c或.cpp文件编译成.o目标文件,或者使用汇编器将.asm文件编译成.o目标文件。

2. 生成动态库:将所有编译好的目标文件生成动态库。使用命令`gcc -shared -o libname.so file1.o file2.o`,其中,-shared选项表示生成动态库,-o选项指定动态库的名称,libname.so为动态库名称,file1.o和file2.o为需要打包的目标文件。

3. 安装动态库:将动态库安装到系统目录中,以便其他程序可以使用。可以使用命令`sudo cp libname.so /usr/lib/`将动态库复制到系统库目录中,或者使用`sudo make install`将动态库安装到系统库目录中。

4. 使用动态库:在需要使用动态库的程序中,可以使用编译器链接动态库,使得程序可以调用库中的函数和变量。使用方法如下:`gcc -o myprogram myprogram.c -L/path/to/lib -lname`,其中,L选项指定动态库所在路径,lname选项指定动态库名称。

四、动态库加载失败的原因与解决办法

五、静态库和动态库的对比

静态库的制作过程
(1) 编写源代码:编写需要包含在静态库中的源代码;
(2) 编译源代码:使用编译器将源代码编译成目标文件;
(3) 链接目标文件:使用静态库工具将所有目标文件链接成一个静态库;
(4) 安装静态库:将静态库文件、头文件和其他必要文件复制到指定目录。
动态库的制作过程
(1) 编写源代码:编写需要包含在动态库中的源代码;
(2) 编译源代码:使用编译器将源代码编译成位置无关的目标文件;
(3) 创建动态库:使用动态库工具将所有目标文件打包成一个动态库;
(4) 安装动态库:将动态库文件、头文件和其他必要文件复制到指定目录,同时设置动态库的搜索路径;
(5) 使用动态库:在程序中使用动态库时,需要使用动态链接器将动态库加载到程序中。
静态库的优点:
1. 静态库在编译时就被链接到程序中,可以提高程序的运行速度和效率。
2. 静态库的使用非常简单,只需要在程序中引用即可,不需要复杂的部署过程。
3. 静态库具有独立性,依赖于静态库的程序可以在没有其他依赖库的情况下运行。

静态库的缺点:
1. 由于静态库的代码被复制到每个使用它的程序中,因此静态库会占用大量的磁盘空间。
2. 静态库的更新需要重新编译程序,不够灵活。
3. 如果静态库的代码更新,所有使用该库的程序都需要重新编译并重新部署。
动态库的优点:
1. 动态库只有在程序运行时才会被加载,因此可以减少内存的使用,降低程序的启动时间。
2. 动态库可以在运行时被更新和替换,非常灵活。
3. 动态库可以被多个程序共享,节约磁盘空间和内存。

动态库的缺点:
1. 动态库的使用复杂,需要在程序中手动加载和卸载动态库。
2. 动态库的运行效率比静态库略低,因为需要在运行时进行链接和加载。
3. 动态库依赖于系统环境,如果系统环境发生变化,可能会导致动态库失效。

六、Makefile

Makefile是一个用于自动化编译程序的工具。它包含了一系列规则,描述了如何从源代码中生成可执行文件。Makefile的基本思想是,只有当源文件或某些依赖项发生变化时,才需要重新编译程序,否则可以直接使用现有的可执行文件,从而提高编译效率。

Makefile规则通常由一个或多个目标(target)、零个或多个依赖项(dependencies)和一系列命令组成。目标是指需要生成的文件或执行的任务,依赖项则是指生成目标所需要的文件或任务,命令则是具体的编译指令。

Makefile的语法格式比较简单,每行由一个目标、一个冒号、其所依赖的文件列表和一个换行符组成。接着是一行或多行的命令,用于生成目标文件。如果目标文件需要依赖其他文件,就需要在Makefile中明确列出依赖关系。

Makefile通常包含了许多规则,用于编译和链接不同的源代码文件。使用Makefile可以简化程序编译的过程,提高编译效率,特别是在大型软件项目中,Makefile的作用更加显著。
Makefile 的文件命名规则非常简单,只需要将文件命名为Makefile 或者makefile 即可。当然,也可以使用其它名称,但需要在执行 make 命令时指定 Makefile 文件的名称。

Makefile 中的规则通常是由多个部分组成,包括目标、依赖和命令三部分。下面是一个典型的 Makefile 规则:

target: dependencies
        command

其中,target 表示目标,通常是指生成的文件名或者执行的任务名称;dependencies 表示依赖,通常是指生成目标所需要的文件或者任务;command 表示命令,通常是指生成目标的具体操作指令。

Makefile 中的规则可以有多个,每个规则之间需要用空行隔开。对于一个 Makefile 文件,通常会包含多个规则,用于编译和链接不同的源代码文件。使用 Makefile 可以简化程序编译的过程,提高编译效率,特别是在大型软件项目中,Makefile 的作用更加显著。

Makefile是一种用来构建(编译)和管理代码的工具,主要用于自动化构建工程。它的工作原理可以概括为以下几个步骤:

1. Makefile中定义了目标(target)和依赖关系(dependency),以及如何生成目标的规则(recipe)。

2. Make这个命令会读取Makefile文件中的目标和依赖关系,根据规则生成目标文件。

3. Make会检查目标文件和依赖文件的时间戳,如果依赖文件的时间戳比目标文件更晚,那么就需要重新生成目标文件。

4. 根据需要重新生成目标文件,然后更新目标文件的时间戳。

5. 如果有多个目标,Make会根据依赖关系的顺序依次生成每个目标。

通过Makefile可以自动化构建和管理代码,提高开发效率和代码可维护性。
Makefile中的变量用于定义和存储常量值,以便在Makefile的规则和命令中使用。变量名通常用大写字母表示,可以包含字母、数字和下划线。变量的值可以是字符串、文件名、目录名或命令。

Makefile中有两种类型的变量:简单变量和递归变量。简单变量的值在定义时就已经确定,而递归变量的值根据当前的上下文环境动态计算。

下面是一些常用的Makefile变量:

1. CC:编译器的名称。
2. CFLAGS:编译器的选项。
3. LDFLAGS:链接器的选项。
4. SRCS:源代码文件的列表。
5. OBJS:目标文件的列表。
6. LIBS:链接时需要链接的库文件列表。
7. PREFIX:安装Makefile生成的二进制文件的前缀。

在Makefile中,可以使用变量名来代替常量值,以便在Makefile的规则和命令中使用。使用变量可以使Makefile更加灵活和易于维护。
Makefile中的模式匹配用于匹配文件名模式,以便在Makefile中使用相同规则处理不同的文件。模式匹配可以用在目标、依赖、规则和命令中。

Makefile中有两种模式匹配方式:通配符和模式规则。通配符只匹配单个字符或字符集,而模式规则可以匹配任意长度的字符串,可以使用通配符和特殊字符。

下面是一些常用的Makefile模式匹配方式:

1. 通配符

- `*`:匹配任意长度的任意字符。
- `?`:匹配单个任意字符。
- `[ ]`:匹配字符集中的任意一个字符。
- `[^ ]`:匹配不在字符集中的任意一个字符。

例如:

# 匹配所有以.c结尾的文件
SRCS := $(wildcard *.c)

# 匹配所有以abc开头的文件
OBJS := $(wildcard abc*)

2. 模式规则

- `%`:匹配任意长度的任意字符。
- `$(VAR:<%=%>)`:替换变量中的%为其它字符串。

例如:

# 匹配所有以.c结尾的文件,并生成相应的.o文件
%.o: %.c
 gcc -c $< -o $@

# 将SRCS中所有.c文件替换为.o文件
OBJS := $(SRCS:.c=.o)

模式规则的语法是“目标模式: 依赖模式”,其中目标模式和依赖模式中可以使用%通配符,以匹配任意长度的任意字符。在规则中,可以使用自动变量$@、$<、$^等,以便在命令中引用目标文件、依赖文件等信息。

以上是Makefile中模式匹配的一些常用方式,可以根据实际需要进行使用。
Makefile中的函数允许用户在Makefile中进行字符串操作、条件判断、文件操作等操作。Makefile中有很多内置函数,可以通过函数名和参数来调用这些函数。

下面是一些常用的Makefile函数:

1. 字符串函数

- `$(subst from,to,text)`:将text中的from替换为to。
- `$(patsubst pattern,replacement,text)`:将text中符合pattern的部分替换为replacement。
- `$(strip string)`:去除string中的空格。
- `$(wildcard pattern)`:获取符合pattern的文件列表。
- `$(basename names)`:获取names中的文件名部分。
- `$(dir names)`:获取names中的目录部分。
- `$(notdir names)`:获取names中的文件名部分。
- `$(shell command)`:执行shell命令,并返回结果。

例如:

<pre><code>

# 将所有的.c文件替换为.o文件
OBJS := $(patsubst %.c,%.o,$(SRCS))

# 获取文件名列表的目录部分
DIRS := $(dir $(SRCS))

# 获取文件名列表的文件名部分
FILES := $(notdir $(SRCS))
</code></pre>
2. 条件判断函数

- `$(if condition,then-part[,else-part])`:如果condition为真,则返回then-part,否则返回else-part。
- `$(foreach var,list,text)`:将list中的每个元素依次赋值给var,并在text中进行操作。
- `$(filter pattern...,text)`:返回text中符合pattern的部分。
- `$(filter-out pattern...,text)`:返回text中不符合pattern的部分。
- `$(shell command)`:执行shell命令,并返回结果。

例如:

<pre><code>

# 判断SRCS是否为空,如果为空,则使用默认值
ifeq ($(strip $(SRCS)),)
SRCS := src/main.c src/util.c
endif

# 遍历DIRS中的每个目录,并执行相应操作
$(foreach dir,$(DIRS),\
$(shell mkdir -p $(dir)obj))

# 获取SRCS中以util开头的文件列表
UTIL_SRCS := $(filter util%, $(SRCS))
</code></pre>
3. 文件操作函数

- `$(file filename,text)`:将text写入文件filename。
- `$(file < filename)`:读取文件filename的内容。
- `$(file > filename)`:清空文件filename的内容。
- `$(file >> filename)`:将text追加到文件filename的末尾。
- `$(eval text)`:执行text中的命令。

例如:

<pre><code>

# 将"hello, world"写入文件greeting.txt
$(file > greeting.txt,hello, world)

# 读取文件greeting.txt的内容,并赋值给变量GREETING
GREETING := $(file < greeting.txt)

# 清空文件greeting.txt的内容
$(file > greeting.txt)

# 将"hello"追加到文件greeting.txt的末尾
$(file >> greeting.txt,hello)

# 执行命令echo "hello, world!"
$(eval $(shell echo "hello, world!"))
</code></pre>
以上是Makefile中常用的一些函数,可以根据实际需要来进行使用。

七、GDB调试

GDB(GNU调试器)是Linux系统下最为常用的调试工具之一,可以帮助程序员调试C、C++等编程语言的代码。下面是GDB调试器的一些基本命令:

1. 启动程序:gdb program
2. 设置断点:break function 或者 break file:line
3. 运行程序:run
4. 单步执行:step
5. 单步跳过:next
6. 查看变量:print variable
7. 查看栈帧:backtrace
8. 跳出函数:finish
9. 删除断点:delete breakpoints
10. 退出GDB:quit

如果程序出现问题,可以使用GDB来找到问题所在,并修复它。GDB可以让程序停在断点处,以便你检查程序的状态,并控制程序的执行。通过GDB调试器,程序员可以更快地发现程序中的错误,并提高代码的质量。

八、标准C库IO函数和Linux系统IO函数对比

标准C库IO和Linux系统IO之间有很强的关系。事实上,标准C库IO函数是在Linux系统IO之上构建的高级抽象层。标准C库IO函数提供了一组简单易用的API,使得在不同的平台上进行输入和输出操作更加方便和可移植。在Linux系统中,标准C库IO函数实际上使用了Linux系统IO来执行底层的输入和输出操作。

Linux系统IO由操作系统内核提供,是一组基于文件描述符的系统调用,用于进行输入和输出操作。与标准C库IO函数不同,它们更加底层和基本,提供了更多的控制和更高的性能。因此,对于一些需要高性能和更多控制的输入输出场景,开发人员可能会直接使用Linux系统IO系统调用。

总的来说,标准C库IO函数和Linux系统IO是紧密相关的,并且它们协同工作来提供强大的输入输出功能,满足不同的开发需求。

九、虚拟地址空间

虚拟地址空间是指每个进程在内存中可用的虚拟地址的集合。每个进程都有自己的虚拟地址空间,它为进程提供了一种与物理内存分离的抽象机制,使得进程可以独立地使用内存,而不会对其他进程的内存访问造成影响。

虚拟地址是一种由操作系统分配的地址,它可以映射到物理内存中的实际物理地址。当进程请求内存时,操作系统会根据虚拟地址将对应的物理地址映射到进程的虚拟地址空间中,使进程可以使用内存。

虚拟地址空间通常由多个段组成,包括代码段、数据段、堆、栈等。不同的段有不同的访问权限和大小,其中代码段用于存放程序的执行代码,数据段用于存放程序的全局数据,堆和栈用于动态分配内存和函数调用时的临时数据存储。

总之,虚拟地址空间为进程提供了一种抽象机制,使得进程可以独立地使用内存,而不会对其他进程的内存访问造成影响。

十、文件描述符

文件描述符是操作系统中用于标识一个打开文件的整数值。在Linux、Unix、Mac等类Unix系统中,文件描述符是一个非负整数,它在进程中唯一标识一个打开的文件。

当进程打开一个文件时,操作系统会为该进程分配一个文件描述符。进程可以使用该文件描述符来访问该文件,如读取、写入、关闭等操作。每个进程都有一张独立的文件描述符表,它记录了该进程打开的所有文件的信息,包括文件描述符和文件状态标志等。

文件描述符的范围通常是从0开始,最大值是系统定义的最大文件打开数减1。当进程结束时,操作系统会自动关闭该进程打开的所有文件,并回收文件描述符。

在Linux系统中,标准输入stdin、标准输出stdout和标准错误stderr分别对应着文件描述符0、1和2。当进程调用一些系统调用时,如read、write、close等,需要使用文件描述符来指定要操作的文件。

十一、open函数

在Linux系统中,IO函数是用于进行输入输出操作的函数,其定义在不同的头文件中,例如:

- 标准IO函数:在<stdio.h>头文件中,如printf、scanf等函数。
- 文件操作函数:在<fcntl.h>、<unistd.h>等头文件中,如open、read、write等函数。
- 套接字函数:在<sys/socket.h>头文件中,如socket、bind、listen、accept等函数。

这些函数可以用于读取文件、写入文件、打印输出等操作。下面我们简单介绍一些常用的IO函数:

1. 标准IO函数

- printf:格式化输出函数,可以输出各种类型的数据。
- scanf:格式化输入函数,可以输入各种类型的数据。
- getchar:从标准输入流中读入一个字符。
- putchar:将一个字符输出到标准输出流中。
- fgets:从指定文件中读取一行字符。
- fputs:将一行字符写入指定文件中。

2. 文件操作函数

- open:打开指定的文件。
- read:从指定文件中读取数据。
- write:向指定文件中写入数据。
- close:关闭指定的文件。

3. 套接字函数

- socket:创建一个套接字。
- bind:将一个网络地址和套接字绑定在一起。
- listen:监听来自客户端的连接请求。
- accept:接受客户端的连接请求。
- recv:从已连接的套接字中接收数据。
- send:向已连接的套接字中发送数据。
- connect:建立与服务器的连接。

在使用这些函数时,需要注意函数的参数和返回值,并根据需要进行错误处理。此外,在进行文件IO时,还需要注意文件读写位置和文件权限等问题。
open()函数的第一个参数pathname是一个字符串,指定需要打开的文件的路径名。flags参数是一个整数,用于指定打开文件的方式和权限,mode参数是一个权限标志,用于在创建新文件时指定文件的读写权限。

flags参数常用的数值有:

- O_RDONLY:只读方式打开文件
- O_WRONLY:只写方式打开文件
- O_RDWR:读写方式打开文件
- O_CREAT:如果文件不存在则创建文件
- O_TRUNC:如果文件存在则截断文件
- O_APPEND:在文件末尾追加数据

mode参数常用的数值有:

- S_IRWXU:文件所有者的权限,读、写和执行
- S_IRUSR:文件所有者的读权限
- S_IWUSR:文件所有者的写权限
- S_IXUSR:文件所有者的执行权限
- S_IRWXG:文件所属用户组的权限,读、写和执行
- S_IRGRP:文件所属用户组的读权限
- S_IWGRP:文件所属用户组的写权限
- S_IXGRP:文件所属用户组的执行权限
- S_IRWXO:其他用户的权限,读、写和执行
- S_IROTH:其他用户的读权限
- S_IWOTH:其他用户的写权限
- S_IXOTH:其他用户的执行权限

open()函数返回一个非负整数的文件描述符,用于后续的文件读写操作。如果出现错误,返回值为-1,并设置全局变量errno来指示错误类型。

十二、read\write函数

在Linux系统中,read和write函数是用于进行文件IO操作的函数,其定义在<unistd.h>头文件中。它们分别用于从文件中读取数据和向文件中写入数据。

1. read函数

read函数的语法如下:

ssize_t read(int fd, void *buf, size_t count);

其中,fd表示文件描述符,buf表示读取数据的缓冲区,count表示期望读取的字节数。

read函数的返回值为读取到的字节数,如果返回值为0,则表示已经读到文件的末尾。如果返回值为-1,则表示读取数据时出现了错误。

2. write函数

write函数的语法如下:

ssize_t write(int fd, const void *buf, size_t count);

其中,fd表示文件描述符,buf表示要写入的数据的缓冲区,count表示要写入的字节数。

write函数的返回值为写入的字节数,如果返回值小于count,则表示写入数据时出现了错误。

在使用这些函数时,需要注意函数的参数和返回值,并根据需要进行错误处理。此外,在进行文件IO时,还需要注意文件读写位置和文件权限等问题。

十三、lseek函数

lseek函数是Linux中用于文件定位的系统调用之一。它通过改变文件指针的位置来实现对文件的随机访问。

具体来说,lseek函数将文件描述符fd所指向的文件的读写位置移动到距离文件开始处off个字节的位置处。文件的起始位置为0,如果off为正,则表示向文件尾方向移动;如果off为负,则表示向文件头方向移动。

lseek函数的原型如下:

#include<sys/types.h>
#include<unistd.h>
off_t lseek(int fd, off_t offset, int whence);
其中,fd为文件描述符,offset为偏移量,whence表示偏移量的起始位置,有如下三种取值:

SEEK_SET:从文件开始位置计算偏移量
SEEK_CUR:从当前读写位置计算偏移量
SEEK_END:从文件结尾处计算偏移量
lseek函数执行成功时返回新的文件指针位置,失败时返回-1,并设置errno变量指明错误原因。

总之,lseek函数是一种非常有用的文件操作函数,可以方便地实现对文件的定位和修改,也是许多Linux程序中必不可少的一部分。

十四、stat\lstat函数

Linux中的stat()和lstat()函数用于获取文件或符号链接的元数据信息,包括文件类型、权限、所有者、修改时间、大小等。

它们的区别在于,当参数pathname指向一个符号链接时,stat()返回该符号链接所指向的文件的元数据信息,而lstat()返回符号链接本身的元数据信息。如果pathname指向的是一个普通文件或目录,则这两个函数的效果相同。

这两个函数的具体使用方法如下:

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

int stat(const char *pathname, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
其中,pathname是要获取元数据信息的文件路径名,statbuf是一个结构体指针,用于存储获取到的元数据信息。

调用成功后,stat()和lstat()函数都会将获取到的文件信息填入statbuf结构体中,并返回0。若调用失败,则返回-1,并设置errno变量来表示具体的错误原因。

需要注意的是,这两个函数可能会因为没有足够的访问权限而导致失败,因此在调用它们之前需要确保程序有足够的权限来访问指定的文件或符号链接。

十五、文件属性操作函数

Linux系统提供了一些文件属性操作函数,包括chmod、chown、chgrp等函数,其定义在<sys/stat.h>和<unistd.h>头文件中。

1. chmod函数

chmod函数用于修改文件的权限。其语法如下:

<pre><code>

int chmod(const char *path, mode_t mode);
</code></pre>
其中,path表示文件路径,mode表示要设置的文件权限。mode需要使用八进制表示法,如0644表示文件所有者可读写,其他用户只可读取。

chmod函数的返回值为0表示修改权限成功,-1表示修改权限失败。

2. chown函数

chown函数用于修改文件的所有者和所属组。其语法如下:

<pre><code>

int chown(const char *path, uid_t owner, gid_t group);
</code></pre>
其中,path表示文件路径,owner表示要设置的文件所有者的用户ID,group表示要设置的文件所属组的组ID。

chown函数的返回值为0表示修改所有者和所属组成功,-1表示修改所有者和所属组失败。

3. chgrp函数

chgrp函数用于修改文件的所属组。其语法如下:

<pre><code>

int chgrp(const char *path, gid_t group);
</code></pre>
其中,path表示文件路径,group表示要设置的文件所属组的组ID。

chgrp函数的返回值为0表示修改所属组成功,-1表示修改所属组失败。

十六、目录操作函数

opendir:打开一个目录,返回一个DIR类型指针。原型如下:

#include <dirent.h>
DIR *opendir(const char *name);
readdir:读取一个目录的项,返回一个dirent结构体指针。原型如下:

#include <dirent.h>
struct dirent *readdir(DIR *dirp);
其中dirent结构体定义在<dirent.h>头文件中,包括d_ino、d_type、d_name等字段,用于描述文件或子目录的信息。

closedir:关闭一个目录。原型如下:

#include <dirent.h>
int closedir(DIR *dirp);
chdir:改变当前工作目录。原型如下:

#include <unistd.h>
int chdir(const char *path);
mkdir:创建一个新目录。原型如下:

#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
rmdir:删除一个目录。原型如下:

#include <unistd.h>
int rmdir(const char *pathname);
其中,mode参数用于设置新目录的访问权限,可以使用类似chmod命令的数字表示法来指定。

这些目录操作函数是Linux文件系统编程中比较常见的一部分,能够方便地实现对目录的读取、遍历、创建、删除等操作。

十七、目录遍历函数

dup函数和dup2函数可以用于复制文件描述符,常用于进行重定向操作。

1. dup函数

dup函数的原型为:

#include <unistd.h>
int dup(int oldfd);
该函数的作用是复制文件描述符oldfd,并返回一个新的文件描述符。新的文件描述符与oldfd指向同一文件,但是它们有不同的文件描述符值。

dup函数返回的新文件描述符是当前未使用的最小整数值,如果出现错误,则返回-1,并设置errno变量。

2. dup2函数

dup2函数的原型为:

#include <unistd.h>
int dup2(int oldfd, int newfd);
该函数会复制oldfd指向的文件描述符,并将副本的文件描述符号设置为newfd。如果当前进程已经打开了newfd,则先将其关闭,再复制oldfd指向的文件描述符。

如果oldfd和newfd相等,则不进行任何操作,直接返回newfd。

如果出现错误,则返回-1,并设置errno变量。

使用dup和dup2函数,可以实现文件描述符的重定向操作,比如将标准输出重定向到某个文件中。

十九、fcntl函数

Linux中的fcntl函数是一个用于文件控制的系统调用,可以进行一些对文件描述符的属性进行修改或者获取的操作。通常情况下,它被使用于实现一些高级的文件操作,如非阻塞I/O、文件锁定等。

fcntl函数多用于对已打开文件描述符的属性进行修改,其原型如下:

#include <fcntl.h>
int fcntl(int fd, int cmd, ...);
其中,fd为文件描述符,cmd为操作指令,剩余的参数取决于cmd的不同值,一般有以下几种:

F_DUPFD:复制文件描述符,创建一个新的文件描述符,其值根据第三个参数(最小可用的文件描述符)来确定。
F_GETFL:获取文件状态标志(file status flags)。
F_SETFL:设置文件状态标志,其值为O_APPEND、O_NONBLOCK、O_ASYNC等之一或它们的逻辑或组合。
F_GETLK:获取一个文件的锁信息。
F_SETLK:设置一个文件锁,如果请求获取该锁失败,会返回EBUSY错误。
F_SETLKW:与F_SETLK相同,但如果请求获取该锁失败,将会一直等待,直到获取到锁或出错。
fcntl函数执行成功时返回0或者某些特殊值,执行失败时返回-1,并设置errno变量以指示错误原因。

总之,fcntl函数是一个非常重要的文件控制函数,能够方便地实现对文件描述符的控制和管理,是实现高级文件操作的必不可少的一部分。

常用命令

*题外话


本文标题:Linux基础(一)——系统编程入门 - 八卦谈
本文地址:www.ttdhp.com/article/50653.html

天天动画片声明:登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。
扫码关注我们