所謂系統調用其實是操作系統提供給用戶程序的一組“特殊”函數接口,可以直接這麼去理解,操作系統是一個很大的“函數庫”,它給程序員提供了很多可以調用的函數。
系統調用按照功能邏輯大致可分爲:進程控制、進程間通信、文件系統控制、系統控制、內存管理、網絡管理、socket控制、用戶管理。在Linux的不同版本中,提供了兩三百個系統調用,用戶程序可以通過這組接口獲得操作系統(內核)提供的服務。例如,用戶可以通過文件系統相關的系統調用,請求系統打開文件、關閉文件或讀寫文件。下圖是類UNIX系統的軟件層次圖:
應用程序可以通過系統調用接口陷入內核,內核再通過相應驅動程序去控制底層的硬件。當然應用程序進行系統調用有多種方式,如下圖所示:(1)應用程序直接調用系統調用,(2)通過shell命令,(3)通過標準庫函數,其實這些庫函數也都是系統調用的封裝出來的,比如fread()函數就是封裝系統調用read()而來的,當然並不是所有的系統調用都被封裝成了庫函數。
1. 系統調用I/O函數
系統調用中操作I/O的函數,都是針對文件描述符的,通過文件描述符可以直接對相應的文件進行操作,如:open、close、write 、read、ioctl。就像我C語言博文中關於文件操作那篇一樣,無非那些是標準庫下的函數,是對系統調用中操作I/O的函數封裝後的庫函數,原理都是一樣,C標準庫中有關文件的FILE結構體中包含了文件描述符和一些關於流緩衝區的信息。
這裏簡單解釋下文件描述符的概念,文件描述符本質就是一個非負整數,是你在用open系統調用打開現存文件或新建文件時,系統(內核)返回給你的,它用來指定已打開的文件。
#define STDIN_FILENO 0 //標準輸入的文件描述符
#define STDOUT_FILENO 1 //標準輸出的文件描述符
#define STDERR_FILENO 2 //標準錯誤的文件描述符
上面這三個是特殊的文件描述符,在程序運行起來後是默認打開的。
1.1 open函數:打開一個文件
當文件存在時使用:int open(const char *pathname, int flags);
當文件不存在時使用:int open(const char *pathname, int flags, mode_t mode);
參數:pathname:文件的路徑及文件名。
flags:open函數的行爲標誌。
mode:文件權限(可讀、可寫、可執行)的設置。
返回值:成功返回打開的文件描述符,失敗返回-1,可以利用perror去查看原因(下同)。
1.2 close函數:關閉一個文件
int close(int fd);
參數:fd是調用open打開文件返回的文件描述符。
返回值:成功返回0,失敗返回-1。
1.3 read/write函數:把指定數目的數據讀到內存或寫到文件
ssize_t read/write(int fd, const void *addr, size_t count);
參數:fd:文件描述符。
addr:內存首地址/數據首地址。
count:寫入數據的字節個數。
返回值:成功返回實際讀出/寫入數據的字節個數,失敗返回-1。
1.4 remove函數:刪除文件
int remove(const char *pathname);
參數:pathname :文件的路名+文件名。
返回值:成功返回0,失敗返回-1。
1.5 例系統調用實現cp命令
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <unistd.h>//write read
#include <sys/types.h> //open
#include <sys/stat.h>
#include <fcntl.h>
#define BUF_SIZE 1024
int main(int argc,char *argv[])
{
int fd_src,fd_dest;
char buf[BUF_SIZE]="";
int ret = 0;
if(argc != 3)
{
printf("miss parameters,please check your
input!\n");
exit(-1);
}
else
{
fd_src = open(argv[1],O_RDONLY);
fd_dest = open(argv[2],O_WRONLY|O_CREAT,0666);
if((fd_src == -1) || (fd_dest == -1))
{
perror("open
file");
exit(-1);
}
//拷貝到目的文件
ret = read(fd_src,buf,BUF_SIZE);
while(ret > 0)
{
ret
= write(fd_dest,buf,ret);
if(ret
== -1)
{
perror("write file");
exit(1);
}
ret
= read(fd_src,buf,BUF_SIZE);
}
close(fd_src);
close(fd_dest);
}
return 0;
}