C语言与操作系统交互探秘

系统调用与库函数
在 C语言中,系统调用是用户程序与操作系统内核交互的桥梁。以下是常见系统调用的概述:


文件操作类:open()、read()、write()、close()、lseek()
进程控制类:fork()、exec()、wait()、exit()
信号处理类:signal()、kill()
进程间通信:pipe()、shmget()、msgget()
网络通信:socket()、bind()、listen()、accept()
系统调用 vs 库函数:


系统调用是操作系统提供的接口,进入内核态执行
库函数是对系统调用的封装(如 fread 封装了 read)
系统调用开销大但能访问底层资源,库函数效率高且跨平台
工作原理:


用户程序通过特定指令(如 int 0x80 或 syscall)触发系统调用
CPU 切换到内核态执行对应的内核服务例程
内核处理请求并返回结果
CPU 切回用户态继续执行
以下是一个简单的系统调用示例:


#include 
#include
#include

int main() {

int fd;
char buffer[20] = "Hello, World!\n";

// 系统调用:打开文件
fd = open("test.txt", O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
    perror("open failed");
    return 1;
}

// 系统调用:写入文件
write(fd, buffer, 14);

// 系统调用:关闭文件
close(fd);

return 0;

}



 


 



文件操作与 I/O 系统
C语言提供了两套文件操作接口:


标准 I/O 库:fopen()、fread()、fwrite()、fclose() 等
系统调用:open()、read()、write()、close() 等
标准 I/O 与系统调用的关系:


标准 I/O 基于系统调用实现,提供缓冲机制
系统调用直接操作文件描述符,无缓冲
文件系统基础:


inode:存储文件元数据(权限、所有者、时间戳等)
目录结构:目录文件存储文件名到 inode 的映射
文件描述符表:每个进程维护一个打开文件的描述符表
I/O 模型:


阻塞 I/O:操作直到完成才返回
非阻塞 I/O:立即返回,需轮询结果
I/O 多路复用:通过 select/poll/epoll 同时监控多个文件描述符
异步 I/O:操作完成后通过回调通知
以下是一个使用 select 实现的 I/O 多路复用示例:


#include 
#include
#include
#include

int main() {

fd_set readfds;
struct timeval timeout;
int fd_stdin = fileno(stdin);
char buffer[100];

while (1) {
    // 清空文件描述符集
    FD_ZERO(&readfds);
    // 添加标准输入到监控集
    FD_SET(fd_stdin, &readfds);

    // 设置超时时间
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;

    // 调用 select 监控
    int result = select(fd_stdin + 1, &readfds, NULL, NULL, &timeout); https://www.fglt.me/

    if (result < 0) {
        perror("select failed");
        exit(EXIT_FAILURE);
    } else if (result == 0) {
        printf("Timeout occurred!\n");
    } else {
        // 标准输入就绪,读取数据
        if (FD_ISSET(fd_stdin, &readfds)) {
            fgets(buffer, sizeof(buffer), stdin);
            printf("Read: %s", buffer);
        }
    }
}

return 0;

}



 


 



信号处理机制
信号基本概念:


信号是软件中断,用于通知进程发生了异步事件
常见信号:SIGINT(2)、SIGTERM(15)、SIGKILL(9)、SIGSEGV(11)
信号处理方式:


默认处理:执行系统预设动作(如终止进程)
忽略信号:不做任何处理
捕获信号:注册信号处理函数
信号处理函数注意事项:


只能调用异步信号安全的函数
避免执行复杂操作
使用 volatile sig_atomic_t 变量进行进程间通信
以下是一个信号处理的示例:


#include 
#include
#include
#include

volatile sig_atomic_t flag = 0;

// 信号处理函数
void sigint_handler(int signum) {

if (signum == SIGINT) {
    printf("\nCaught SIGINT, setting flag...\n");
    flag = 1;
}

}

int main() {

// 注册信号处理函数
if (signal(SIGINT, sigint_handler) == SIG_ERR) {
    perror("signal registration failed");
    return 1;
}

printf("Running... Press Ctrl+C to exit.\n");

// 主循环
while (!flag) {
    printf("Working...\n");
    sleep(1);
}

printf("Exiting gracefully...\n");
return 0;

}



 


 



信号在进程间通信中的应用:


使用 kill() 函数向指定进程发送信号
使用 sigqueue() 可以传递附加数据
信号是一种简单但有限的进程间通信方式

免费获取专属报价方案,请联系我们:
C语言与操作系统交互探秘联系方式