fcntl()
和ioctl()
是用于对文件描述符进行控制的两个系统调用,它们在不同的情况下有不同的用途和功能。
1、fcntl()函数
fcntl()
函数提供了对已打开文件描述符执行各种控制操作的功能,例如复制文件描述符(与dup
、dup2
类似)、获取/设置文件描述符标志、获取/设置文件状态标志等,是一个多功能的文件描述符管理工具。可通过"man 2 fcntl"命令查看fcntl()
函数的原型。
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */);
函数fcntl()
的参数和返回值含义如下:
fd
:文件描述符。cmd
:操作命令。用于指定对文件描述符fd
执行的操作类型。这些命令通常以F_XXX
开头,如F_DUPFD
、F_GETFD
、F_SETFD
等,具体命令的作用可以通过查阅手册页面(man 2 fcntl
)了解,常见的功能包括:- 复制文件描述符(
F_DUPFD
或F_DUPFD_CLOEXEC
); - 获取/设置文件描述符标志(
F_GETFD
或F_SETFD
); - 获取/设置文件状态标志(
F_GETFL
或F_SETFL
); - 获取/设置异步 IO 所有权(
F_GETOWN
或F_SETOWN
); - 获取/设置记录锁(
F_GETLK
或F_SETLK
)。
- 复制文件描述符(
...
:fcntl()
函数是一个可变参数函数,第三个参数根据不同的cmd
需要传入相应的实参。- 返回值:若执行失败,则返回
-1
并设置errno
;若执行成功,则返回值与cmd
(操作命令)有关。例如,F_DUPFD
(复制文件描述符)将返回一个新的文件描述符,F_GETFD
(获取文件描述符标志)将返回文件描述符标志,F_GETFL
(获取文件状态标志)将返回文件状态标志等。
示例用法:
代码语言:javascript复制#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
// 获取文件描述符标志
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
perror("fcntl");
close(fd);
return 1;
}
// 设置文件描述符标志,添加非阻塞标志
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
perror("fcntl");
close(fd);
return 1;
}
// 其他操作...
close(fd);
return 0;
}
2、ioctl()函数
ioctl()函数可视为文件IO操作的多功能工具箱,可处理各种杂项且不统一的任务,通常用于与特殊文件或硬件外设交互。
本篇博文只是介绍此系统调用,具体用法将在进阶篇中详细探讨,例如可以利用ioctl获取LCD相关信息等。ioctl()函数原型如下所示(可通过"man 2 ioctl"命令查看):
代码语言:javascript复制#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
函数ioctl()参数和返回值含义如下:
fd
:文件描述符。request
:用于指定要执行的操作,具体值与操作对象有关,后续会详细介绍。...
:可变参数列表,根据request
参数确定具体参数,用于与请求相关的操作。- 返回值:成功时返回 0,失败时返回 -1。
示例用法:
代码语言:javascript复制#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/fs.h>
int main() {
int fd = open("/dev/sda", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
// 查询设备块大小
long block_size;
if (ioctl(fd, BLKSSZGET, &block_size) == -1) {
perror("ioctl");
close(fd);
return 1;
}
printf("Block size: %ld bytesn", block_size);
// 其他操作...
close(fd);
return 0;
}