操作系统的职责
操作系统用来管理所有的资源,并将不同的设备和不同的程序关联起来。
什么是Linux系统编程
在有操作系统的环境下编程,并使用操作系统提供的系统调用及各种库,对系统资源进行访问。
系统编程主要就是为了让用户能够更好和更方便的操作硬件设备,并且对硬件设备也起到保护作用。我们所写的程序,本质就是对硬件设备的操作,所以操作系统提供接口可以对硬件进行操作。
系统调用概述:
本质都是要对硬件设备进行操作,但是Linux操作系统在硬件之上设置了内核,也就是只有内核才可以直接操作硬件设备,如果想操作内核,需要调用内核的系统调用,如果要操作内核中的系统调用,有三种方式:
第一种:shell,用户通过shell命令,由shell解释器操作内核的系统调用。
第二种:库函数,用户通过应用层库函数的接口,比如fread对内核的系统调用进行操作。
第三种:应用层系统调用,它可以直接对内核的系统调用进行操作。
系统调用时操作系统提供给用户程序的一组“特殊”的函数接口。
Linux的不同版本提供了两三百个系统调用。
用户程序可以通过这组接口获得操作系统(内核)提供的服务。
系统调用按照功能逻辑大致可分为:
进程控制、进程间通信、文件系统控制、系统控制、内存管理、网络管理、socket控制、用户管理。
系统调用的返回值:
通常,用一个非负的返回值来表明错误,返回一个0值表明成功。
错误信息存放在全局变量errno中,用户可用perror函数打印出错信息。
系统调用遵循的规范:
在Linux中,应用程序编程接口(API)遵循POSIX标准。
系统调用I/O函数
文件描述符:
文件描述符是非负整数。打开现存文件或新建文件时,系统(内核)会返回一个文件描述符。文件描述符用来指定已打凯的文件。
在系统调用(文件IO)中,文件描述符对文件起到标识作用,如果要操作文件,就是对文件描述符的操作。
当一个程序运行或一个进程开启时,系统会自动创建三个文件描述符。
#define STDIN_FILENO 0 //标准输入的文件描述符
#define STDOUT_FILENO 1 //标准输出的文件描述符
#define STDERR_FILENO 2 //标准错误的文件描述符
如果自己打开文件,会返回文件描述符,而文件描述符一般按照从小到大依次创建的顺序。
#include
#include
#include
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
功能:
代开文件,如果文件不存在则可以选择创建。
参数:
pathname:文件的路径及文件名。
flags:打开文件的行为标志,必选项 O_RDONLY, O_WRONLY, O_RDWR
mode:这个参数,只有在文件不存在时有效,指新建文件时指定文件的权限。
返回值:
成功:文件描述符
失败:-1
flags详细说明
文件最终权限:mode & ~umask
shell进程的umask掩码可以用umask命令查看
umask:查看掩码(补码)
umask mode:设置掩码,mode为八进制数
umask -S:查看各组用户的默认操作权限
代码示例:
#include
#include
#include
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("Failed to open the file");
exit(1);
}
// 在这里可以继续处理打开的文件
close(fd); // 关闭文件
return 0;
}
perror函数:
#include
void perror(const char *s);
#include
功能:
perror函数根据当前的错误代码,将与该错误代码对应的错误消息打印到标准错误流(stderr)中。
参数:
s是一个字符串,可用于自定义错误消息前缀。
返回值:
无
error函数:
#include
void error(int status, int errnum, const char *format, ...);
功能:
error函数将错误消息打印到标准错误流,并以给定的格式输出。它与perror函数相似,但提供了更多的灵活性,可以根据需要自定义错误消息的格式。
参数:
status:表示错误的严重程度,通常为非零值表示致命错误。
errnum:表示具体的错误代码,可以使用errno变量作为参数传递。
format:一个格式化字符串,类似于printf函数的格式。
...:可选的附加参数,用于填充格式化字符串中的占位符。
返回值:无
代码示例:
#include
#include
#include
int main() {
FILE* file = fopen("nonexistent.txt", "r");
if (file == NULL) {
perror("Failed to open the file");
exit(1);
}
// 在这里可以继续处理打开的文件
fclose(file); // 关闭文件
return 0;
}
#include int close(int fd);
功能:
关闭已打开的文件
参数:
fd : 文件描述符,open()的返回值
返回值:
成功:0
失败: -1, 并设置errno
代码示例:
#include
#include
#include
#include
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("Failed to open the file");
exit(1);
}
// 在这里可以继续处理打开的文件
if (close(fd) == -1) {
perror("Failed to close the file");
exit(1);
}
return 0;
}
#include
ssize_t write(int fd, const void *buf, size_t count);
功能:
把指定数目的数据写到文件(fd)。
参数:
fd:文件描述符
buf:数据首地址
count:写入数据的长度(字节)
返回值:
成功:实际写入数据的字节个数
失败:-1
代码示例:
#include
#include
#include
#include
int main() {
int fd = open("example.txt", O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
perror("Failed to open the file");
exit(1);
}
const char* data = "Hello, World!";
ssize_t bytes_written = write(fd, data, strlen(data));
if (bytes_written == -1) {
perror("Failed to write to the file");
exit(1);
}
// 在这里可以继续处理打开的文件
if (close(fd) == -1) {
perror("Failed to close the file");
exit(1);
}
return 0;
}