termios 结构体:Linux/Unix 终端控制的核心
在 Linux/Unix 系统中,终端设备的行为由 termios 结构体 统一管理。它是 POSIX 标准定义的终端接口核心,通过配置其成员变量可以精确控制终端的输入、输出、控制和本地模式。本文将深入解析 termios 结构体的核心成员、四种关键模式,并提供终端控制的实用示例。
一、termios 结构体的核心成员
termios 结构体定义在 <termios.h> 头文件中,主要包含以下成员:
| 成员 | 类型 | 描述 |
|---|---|---|
c_iflag | tcflag_t | 输入模式标志 |
c_oflag | tcflag_t | 输出模式标志 |
c_cflag | tcflag_t | 控制模式标志 |
c_lflag | tcflag_t | 本地模式标志 |
c_cc | cc_t[] | 控制字符数组 |
c_ispeed | speed_t | 输入波特率 |
c_ospeed | speed_t | 输出波特率 |
其中,c_iflag、c_oflag、c_cflag、c_lflag 是控制终端行为的四大核心模式,我们将在下文详细解释。
二、四大模式详解
1. 输入模式(c_iflag)
输入模式控制终端如何处理输入字符,主要包含以下常见标志:
| 标志 | 描述 |
|---|---|
IGNBRK | 忽略 BREAK 条件 |
BRKINT | BREAK 条件产生 SIGINT 信号 |
IGNPAR | 忽略校验错误的字符 |
PARMRK | 标记校验错误的字符 |
INPCK | 启用输入校验 |
ISTRIP | 剥离字符的第 8 位 |
INLCR | 将 NL(换行)转换为 CR(回车) |
ICRNL | 将 CR(回车)转换为 NL(换行) |
IGNCR | 忽略 CR(回车) |
IXON | 启用输出 XON/XOFF 流控制 |
IXOFF | 启用输入 XON/XOFF 流控制 |
2. 输出模式(c_oflag)
输出模式控制终端如何处理输出字符,主要包含以下常见标志:
| 标志 | 描述 |
|---|---|
OPOST | 启用输出处理 |
ONLCR | 将 NL(换行)转换为 CR-NL(回车-换行) |
OCRNL | 将 CR(回车)转换为 NL(换行) |
ONOCR | 行首的 CR 不输出 |
ONLRET | NL 执行 CR 功能 |
OFILL | 用填充字符代替延时 |
OFDEL | 填充字符为 DEL(否则为 NUL) |
3. 控制模式(c_cflag)
控制模式主要涉及终端的硬件设置,如波特率、数据位、停止位、奇偶校验等:
| 标志 | 描述 |
|---|---|
CLOCAL | 忽略调制解调器状态线 |
CREAD | 启用接收 |
CSIZE | 数据位掩码(CS5/CS6/CS7/CS8) |
CSTOPB | 使用 2 个停止位(否则 1 个) |
PARENB | 启用奇偶校验 |
PARODD | 使用奇校验(否则偶校验) |
HUPCL | 关闭时挂断调制解调器 |
CSTOPB | 使用两个停止位 |
4. 本地模式(c_lflag)
本地模式控制终端的本地行为,如回显、信号生成等:
| 标志 | 描述 |
|---|---|
ISIG | 启用信号生成(如 Ctrl+C 产生 SIGINT) |
ICANON | 启用规范模式(行缓冲) |
ECHO | 回显输入字符 |
ECHOE | 擦除字符时回显退格-空格- 退格 |
ECHOK | 回显换行符 |
ECHONL | 即使 ECHO 关闭也回显 NL |
NOFLSH | 不刷新输入输出队列 |
IEXTEN | 启用扩展输入处理 |
三、控制字符数组(c_cc)
c_cc 数组定义了终端的特殊控制字符,常用的有:
| 索引 | 控制字符 | 描述 |
|---|---|---|
VEOF | Ctrl+D | 文件结束符 |
VEOL | Ctrl+J | 行结束符 |
VEOL2 | Ctrl+K | 备用行结束符 |
VERASE | Ctrl+H | 擦除字符 |
VKILL | Ctrl+U | 擦除整行 |
VINTR | Ctrl+C | 中断信号 |
VQUIT | Ctrl+\ | 退出信号 |
VSUSP | Ctrl+Z | 挂起信号 |
四、终端控制的实用示例
示例 1:禁用回显(密码输入场景)
在输入密码时,通常需要禁用终端回显。以下是实现代码:
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
int main() {
struct termios oldt, newt;
char password[20];
// 获取当前终端设置
tcgetattr(STDIN_FILENO, &oldt);
// 复制设置
newt = oldt;
// 禁用回显
newt.c_lflag &= ~ECHO;
// 应用新设置
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
printf("Enter password: ");
fgets(password, sizeof(password), stdin);
printf("\nPassword entered: %s", password);
// 恢复原设置
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return 0;
}示例 2:设置波特率
以下代码将终端波特率设置为 9600:
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = open("/dev/ttyS0", O_RDWR);
struct termios options;
// 获取当前设置
tcgetattr(fd, &options);
// 设置输入输出波特率为 9600
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
// 设置数据位为 8 位
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// 无校验
options.c_cflag &= ~PARENB;
// 1 个停止位
options.c_cflag &= ~CSTOPB;
// 应用设置
tcsetattr(fd, TCSANOW, &options);
close(fd);
return 0;
}示例 3:启用非规范模式(实时输入)
在非规范模式下,终端不进行行缓冲,输入字符立即被处理:
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
int main() {
struct termios oldt, newt;
char ch;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
// 禁用规范模式和回显
newt.c_lflag &= ~(ICANON | ECHO);
// 设置最小输入字符数和超时时间
newt.c_cc[VMIN] = 1; // 至少 1 个字符
newt.c_cc[VTIME] = 0; // 不超时
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
printf("Press any key (Ctrl+C to exit): ");
while (1) {
read(STDIN_FILENO, &ch, 1);
printf("\nYou pressed: %c (ASCII: %d)\n", ch, ch);
}
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return 0;
}五、总结
termios 结构体是 Linux/Unix 系统终端控制的核心,通过配置其四大模式(输入、输出、控制、本地)和控制字符数组,可以实现对终端行为的精确控制。常见的应用场景包括密码输入(禁用回显)、串口通信(设置波特率)、实时输入处理(非规范模式)等。理解并掌握 termios 结构体的使用,对于开发需要与终端交互的程序至关重要。
(此内容由 AI 辅助生成,仅供参考)