嵌入式开发中fcntl()函数和 ioctrl()函数区别
fcntl()和 ioctrl()函数区别
·
一. 简介
本文来简单学习一下,嵌入式开发中,fcntl()函数和 ioctrl()函数使用过程中的区别。
二. fcntl()和 ioctrl()函数区别
1. 核心区别
fcntl() 和 ioctl() 是 Linux 系统中两个重要的系统调用,它们都用于对文件或设备进行控制操作,但设计目的、使用场景和功能有显著区别。
核心区别对比:
| 维度 | fcntl() |
ioctl() |
|---|---|---|
| 设计目标 | 标准化接口,处理通用文件描述符操作 | 灵活接口,处理设备特定的控制操作 |
| 适用范围 | 所有文件描述符(常规文件、管道、设备等) | 主要用于设备文件(字符设备、块设备、网络设备等) |
| 命令标准化 | 命令由系统统一定义(如 F_GETFL、F_SETFL) |
命令由设备驱动自定义,通常与设备类型强相关 |
| 参数风格 | 固定参数格式:int fcntl(int fd, int cmd, ...) |
可变参数格式:int ioctl(int fd, unsigned long cmd, ...) |
| 可移植性 | 高(系统调用和命令跨平台统一) | 低(设备驱动自定义命令,跨平台差异大) |
2. 具体分析
(1) fcntl():通用文件描述符控制
fcntl(file control)的核心是对文件描述符进行标准化的通用操作,其命令由系统统一定义,适用于所有类型的文件描述符(包括普通文件、管道、套接字、设备文件等)。
主要功能:
- 文件状态标志操作:获取 / 设置文件状态标志(如
O_NONBLOCK非阻塞模式、O_APPEND追加模式),对应命令F_GETFL(获取)和F_SETFL(设置)。
int flags = fcntl(fd, F_GETFL, 0); // 获取当前标志
fcntl(fd, F_SETFL, flags | O_NONBLOCK); // 设置非阻塞模式
- 文件锁管理:实现记录锁(record locking),如
F_LOCK(加锁)、F_UNLOCK(解锁),用于多进程同步。例如:
for (int i = 0; i < 64; i++) {
char dev[64];
sprintf(dev, "/dev/hidraw%d", i);
fd = open(dev, O_RDWR);
//成功usb打开设备
if(fd > 0)
{
//Get Raw Info
res = ioctl(fd, HIDIOCGRAWINFO, &info);
if (res < 0)
{
perror("HIDIOCGRAWINFO");
}
else
{
sprintf(tmp,"0x%04hx 0x%04hx", info.vendor, info.product);
if(strstr(tmp,"0x0123") != NULL && strstr(tmp,"0xa1b2") != NULL)
{
//锁的类型
lock.l_type = F_WRLCK;
//加锁整个文件
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
//对设备文件描述符进行加锁
if(fcntl(fd, F_SETLK, &lock) < 0)
{
perror("fcntl");
if(fcntl(fd,F_GETLK, &lock) < 0)
{
perror("fcntl");
printf("lock.l_type:%d.\n",lock.l_type);
return -1;
}
if(lock.l_type != F_UNLCK)
{
printf("lock.l_type:%d.\n",lock.l_type);
return -2;
}
return -1;
}
return(fd);
}
}
close(fd);
}
}
- 复制文件描述符:
F_DUPFD复制文件描述符,类似dup()但更灵活。 - 信号驱动 I/O:设置文件描述符就绪时的信号通知(如
F_SETOWN指定接收信号的进程)。
特点:
- 命令是标准化的(由 POSIX 定义),跨系统(如 Linux、macOS)行为一致。
- 操作对象是 “文件描述符” 本身的属性,与底层设备类型无关。
(2) ioctl():设备特定控制
ioctl(I/O control)的核心是针对特定设备的自定义控制操作,其命令由设备驱动程序定义,主要用于硬件设备(如串口、网卡、块设备等)的特殊配置。
主要功能:
- 设备参数配置:如串口的波特率(
TIOCGSERIAL获取、TIOCSSERIAL设置)、网卡的 MAC 地址配置。
struct termios tty;
ioctl(fd, TCGETS, &tty); // 获取串口配置
tty.c_cflag = B9600 | CS8 | CLOCAL | CREAD; // 设置波特率9600、8位数据位
ioctl(fd, TCSETS, &tty); // 应用配置
- 设备状态查询:如获取磁盘分区表、检查摄像头是否正在录制。
- 特殊 I/O 操作:如控制 LED 闪烁、触发设备重置、读取传感器原始数据等。
特点:
- 命令是 “设备相关” 的,通常由驱动开发者自定义(需避免与系统保留命令冲突)。
- 接口灵活但缺乏标准化,不同设备的
ioctl命令和参数格式可能完全不同(如串口和网卡的ioctl命令无交集)。 - 可移植性差,同一功能在不同系统或设备上的
ioctl实现可能不同。
三. 总结
使用 fcntl()函数,ioctrl()函数,这两个如何选择?
- 用
fcntl():当需要操作通用文件描述符属性(如非阻塞模式、文件锁),且希望代码跨平台兼容时。 - 用
ioctl():当需要与特定硬件设备交互(如配置设备参数、获取设备特有状态),且接受代码与设备驱动强耦合时。
fcntl()函数 是 “通用标准化接口”,专注于文件描述符的共性操作;
ioctl() 函数是 “设备专用接口”,专注于设备的个性化控制。
两者互补:fcntl()函数 保证了文件操作的统一性和可移植性,ioctl()函数 则为设备驱动提供了灵活扩展的空间。
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐



所有评论(0)