1. 返回错误处理
在 Linux 系统下对常见的错误做了一个编号,每一个 编号都代表着每一种不同的错误类型,当函数执行发生错误的时候,操作系统会将这个错误所对应的编号 赋值给 errno 变量,每一个进程都维护了自己的 errno 变量,它是程序中的全局变量,该变量用于存储就近发生的函数执行错误编号,也就意味着下一次的错误码会覆盖上一次的错误码。 errno 本质上是一个 int 类型的变量,用于存储错误编号,但是需要注意的是,并不是执行所有的系统调用或C 库函数出错时,操作系统都会设置 errno ,具体的可以查看相关的手册。 以 常用的 open 函数来说,当函数返回错误时会设置 errno。 但是errno只是一个编号:#include <stdio.h>
#include <errno.h>
int main(void)
{
printf("%d\n", errno);
return 0;
}
打印出来的只是一个数值,那么想知道具体的错误信息就要用到相关的函数。
strerror 函数:该函数可以将对应的 errno 转换成适合我们查看的字符串信息,其函数原型如下:#include <string.h>
char *strerror(int errnum);
函数参数和返回值解释如下:
errnum
:
错误编号
errno
。
返回值:
对应错误编号的字符串描述信息。
比较简单,可以自行编写一个简单代码测试。
第二个函数是:
perror 函数:
调用此函数不需要传入
errno
,函数内部会自己去获取
errno
变量的值,调用此函数会直接将错误提示字符串打印出来,而不是返回字符串,除此之外还可以在输出的错误提示字符串之前加入自己的打印信息,函数原型如下:
#include <stdio.h>
void perror(const char *s);
函数参数和返回值解释如下:
s
:
在错误提示字符串信息之前,可加入自己的打印信息,也可不加,不加则传入空字符串即可。
返回值:
void
无返回值。
例子如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int fd;
/* 打开文件 */
fd = open("./test", O_RDONLY);
if (-1 == fd) {
perror("open error");
return -1;
}
close(fd);
return 0;
}
结果:
2. exit、_exit、_Exit
有过编程经验的朋友都知道使用 return ,一般原则程序执行正常退出 return 0 ,而执行函数出错退出 return -1,在 Linux 系统下,进程正常退出除了可以使用 return 之外,还可以使用 exit() 、 _exit() 以及 _Exit()。 调用 _exit() 函数会 清除其使用的内存空间,并销毁其在内核中的各种数据结构,关闭进程的所有文件描述符,并结束进程、将控制权交给操作系统。_exit() 函数原型如下:#include <unistd.h>
void _exit(int status);
调用函数需要传入
status
状态标志,
0
表示正常结束、若为其它值则表示程序执行过程中检测到有错误发生。
_exit()和_Exit()
两者等价,用法作用是一样的。
exit()
函数
_exit()
函数都是用来终止进程的,
exit()
是一个标准
C
库函数,而
_exit()
和
_Exit()
是系统调用。 执行 exit()
会执行一些清理工作,最后调用
_exit()
函数。
exit()
函数原型如下:
#include <stdlib.h>
void exit(int status);
该函数的用法和_exit()、_Exit()是 一样的。
3. O_APPEND 和 O_TRUNC
O_TRUNC 这个标志的作用非常简单,如果使用了这个标志,调用 open 函数打开文件的时候会将文件原本的内容全部丢弃,文件大小变为 0。 如果 open 函数携带了 O_APPEND 标志,调用 open 函数打开文件, 当每次使用 write() 函数对文件进行写操作时,都会自动把文件当前位置偏移量移动到文件末尾,从文件末尾开始写入数据,也就是意味着每次写入数据都是从文件末尾开始。 这两个标志的位置和前面所说的open函数其他标志的语法一致,不懂得朋友可以看下面这篇: 文件I/O基础https://blog.csdn.net/YYYYYYJJJJJYYYYY/article/details/144212871 但是两点需要注意: 第一,O_APPEND 标志并不会影响读文件,当读取文件时,O_APPEND 标志并不会影响读位置偏移量,即使使用了 O_APPEND标志,读文件位置偏移量默认情况下依然是文件头。 第二,使用了 O_APPEND 标志,即使是通过 lseek 函数也是无法修改写文件时对应的位置偏移量,写入数据依然是从文件末尾开始,lseek 并不会该变写位置偏移量。4. 复制文件描述符
dup 函数用于复制文件描述符,此函数原型如下:#include <unistd.h>
int dup(int oldfd);
函数参数和返回值解释如下:
oldfd
:
需要被复制的文件描述符。
返回值:
成功时将返回一个新的文件描述符,由操作系统分配,分配置原则遵循文件描述符分配原则; 如果复制失败将返回-1
,并且会设置
errno
值。
dup2 函数:dup 系统调用分配的文件描述符是由系统分配的,遵循文件描述符分配原则,并不能自己指定一个文件描述符,这是 dup 系统调用的一个缺陷;而
dup2 系统调用修复了这个缺陷,可以手动指定文件描述符,而不需要遵循文件描述符分配原则。
dup2 函数原型如下:
#include <unistd.h>
int dup2(int oldfd, int newfd);
函数参数和返回值解释如下:
oldfd
:
需要被复制的文件描述符。
newfd
:
指定一个文件描述符(需要指定一个当前进程没有使用到的文件描述符)。
返回值:
成功时将返回一个新的文件描述符,也就是手动指定的文件描述符
newfd
;如果复制失败将返回-1
,并且会设置
errno
值。
注意:复制得到的文件描述符与原文件描述符都指向同一个文件表,所以它们的文件读写偏移量是一样的 。(跟多次open打开同一个文件有所不同)
5. fcntl 函数
fcntl() 函数可以对一个已经打开的文件描述符执行一系列控制操作,譬如复制一个文件描述符(与 dup 、 dup2 作用相同)、获取 / 设置文件描述符标志、获取 / 设置文件状态标志等,类似于一个多功能文件描述符管理工具箱。fcntl() 函数原型如下:#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ )
函数参数和返回值含义如下:
fd
:
文件描述符。
cmd
:
操作命令。此参数表示我们将要对
fd
进行什么操作,
cmd
参数支持很多操作命令,cmd 操作命令大致可以分为以下
5
种功能:
1.
复制文件描述符(
cmd=F_DUPFD
或
cmd=F_DUPFD_CLOEXEC
);
2.
获取
/
设置文件描述符标志(
cmd=F_GETFD
或
cmd=F_SETFD
);
3.
获取
/
设置文件状态标志(
cmd=F_GETFL
或
cmd=F_SETFL
);
4.
获取
/
设置异步
IO
所有权(
cmd=F_GETOWN
或
cmd=F_SETOWN
);
5.
获取
/
设置记录锁(
cmd=F_GETLK
或
cmd=F_SETLK
);
…
:
fcntl
函数是一个可变参函数,第三个参数需要根据不同的
cmd
来传入对应的实参,配合
cmd
来使用。
返回值:
执行失败情况下,返回
-1
,并且会设置
errno
;执行成功的情况下,其返回值与
cmd
(操作命令)有关,譬如 cmd=F_DUPFD
(复制文件描述符)将返回一个新的文件描述符、
cmd=F_GETFD
(获取文件描述符标志)将返回文件描述符标志、cmd=F_GETFL
(获取文件状态标志)将返回文件状态标志等。
例子:
(1)
复制文件描述符
语法举例(实际情况应用即可)
fd2 = fcntl(fd1, F_DUPFD, 0);//复制fd1
要传入第三个参数,第 三个参数用于指出新复制出的文件描述符是一个大于或等于该参数的可用文件描述符(没有使用的文件描述符);如果第三个参数等于一个已经存在的文件描述符,则取一个大于该参数的可用文件描述符。
(2)
获取
/
设置文件状态标志
cmd=F_GETFL
可用于获取文件状态标志,
cmd=F_SETFL
可用于设置文件状态标志。
cmd=F_GETFL
时 不需要传入第三个参数,返回值成功表示获取到的文件状态标志;cmd=F_SETFL
时,需要传入第三个参数, 此参数表示需要设置的文件状态标志。
但是文件权限标志(
O_RDONLY
、
O_WRONLY
、
O_RDWR
)以及文件创建标志(
O_CREAT
、
O_EXCL
、
O_NOCTTY
、
O_TRUNC
)不能被设置、会被忽略;在
Linux
系统中,只有
O_APPEND
、
O_ASYNC、O_DIRECT
、
O_NOATIME
以及
O_NONBLOCK
这些标志可以被修改
/* 获取文件状态标志 */
flag = fcntl(fd, F_GETFL);
/* 设置文件状态标志,添加 O_APPEND 标志 */
ret = fcntl(fd, F_SETFL, flag | O_APPEND);
6. 截断文件
使用系统调用 truncate()或 ftruncate() 可将普通文件截断为指定字节长度,其函数原型如下:#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
这两个函数的区别在于:
ftruncate()
使用文件描述符
fd
来指定目标文件,而
truncate()
则直接使用文件路 径 path
来指定目标文件,其功能一样。
这两个函数都可以对文件进行截断操作,将文件截断为参数
length 指定的字节长度。如果文件目前的
大小大于参数 length 所指定的大小,则多余的数据将被丢失。如果文件目前的
大小小于参数 length 所指定的大小,则将其进行扩展,对扩展部分进行读取将得到空字
节"\0"
。
调用这两个函数并不会导致文件读写位置偏移量发生改变,所以截断之后一般需要重新设置文件当前的读写位置偏移量,以免由于之前所指向的位置已经不存在而发生错误。
调用成功返回
0
,失败将返回
-1
,并设置
errno
以指示错误原因。
不断学习中,共勉!!!
标签:文件,函数,int,cmd,嵌入式,描述符,详解,Linux,include
From: https://blog.csdn.net/YYYYYYJJJJJYYYYY/article/details/144237624