C标准函数与系统函数

1.C标准函数

库函数(Library function)是把函数放到库里,供别人使用的一种方式.方法是把一些常用到的函数编完放到一个文件里,供不同的人进行调用,一般放在.lib文件中.
库函数调用则是面向应用开发的,库函数可分为两类,一类是c语言标准规定的库函数,一类是编译器特定的库函数。
(由于版权原因,库函数的源代码一般是不可见的,但在头文件中你可以看到它对外的接口).
glibc 是 Linux 下使用的开源的标准 C 库,
它是 GNU 发布的 libc 库,即运行时库.这些基本函数都是被标准化了的,而且这些函数通常都是用汇编直接实现的.
glibc 为程序员提供丰富的 API(Application Programming Interface),我们经常说到的POSIX(Portable Operating System Interface of Unix)
是针对API的标准,即针对API的函数名,返回值,参数类型等.POSIX兼容也就指定这些接口函数兼容,但是并不管API具体如何实现.
随着系统提供的这些库函数把系统调用进行封装或者组合,可以实现更多的功能,这样的库函数能够实现一些对内核来说比较复杂的操作.
比如,fread()函数根据参数,直接就能读文件,而背后隐藏的比如文件在硬盘的哪个磁道,哪个扇区,加载到内存的哪个位置等等这些操作,
程序员是不必关心的,这些操作里面自然也包含了系统调用。而对于第三方的库,它其实和系统库一样,只是它直接利用系统调用的可能性要
小一些,而是利用系统提供的API接口来实现功能(API的接口是开放的)。部分Libc库中的函数的功能的实现还是借助了系统掉调用,比如
printf的实现最终还是调用了write这样的系统调用;而另一些则不会使用系统调用,比如strlen, strcat, memcpy等。

2.系统函数

由操作系统实现提供的所有系统调用所构成的集合即程序接口或应用编程接口(Application Programming Interface,API)。是应用程序同系统之间的接口。

系统调用是通向操作系统本身的接口,是面向底层硬件的。通过系统调用,可以使得用户态运行的进程与硬件设备(如CPU、磁盘、打印机等)进行交互,是操作系统留给应用程序的一个接口。下面适用于访问设备驱动程序的系统调用:
open: 打开文件或设备 
read: 从打开的文件或设备中读取数据 
write: 向打开的文件或设备中写入数据 
close: 关闭文件或设备 
ioctl: 把控制信息传递给设备驱动文件

用户进程需要发生系统调用时,内核将调用内核相关函数来实现(如sys_read(),sys_write(),sys_fork())。用户程序不能直接调用这些函数,这些函数运行在内核态,CPU 通过软中断切换到内核态开始执行内核系统调用函数。
用户态–>系统调用–>内核态–>返回用户态.
实际上使用系统调用会影响系统的性能,在执行调用时的从用户态切换到内核态,再返回用户态会有系统开销。为了减少开销,因此需要减少系统调用的次数,并且让每次系统调用尽可能的完成多的任务。硬件也会限制对底层系统调用一次所能写的数据块的大小。为了给设备和文件提供更高层的接口,Linux系统提供了一系列的标准函数库。使用标准库函数,可以高效的写任意长度的数据块,库函数在数据满足数据块长度要求时安排执行底层系统调用。
一般地,操作系统为了考虑实现的难度和管理的方便,它只提供一少部分的系统调用,这些系统调用一般都是由C和汇编混合编写实现的,其接口用C来定义,而具体的实现则是汇编,这样的好处就是执行效率高,而且,极大的方便了上层调用。

 

3.C标准库函数与系统函数的比较

1.系统函数与操作系统连接更加紧密,能做的事情更多;
2.C标准库函数跨平台性更好,但是功能没有系统调用的强大.
3.C标准函数是有文件缓冲区的,系统函数则有内核缓冲区.




知识回归:
每一个FILE文件流里面有什么?
inode--即我们所说的文件描述符,指向磁盘中真正的文件
f_pos--读写指针的位置
buffer--缓冲区指针,指向一块缓冲区,大小是8192B.


缓冲区的作用是什么?
减少I/O,提高效率.

如何去刷新缓冲区?
fflush
\n 只能刷新终端文件,stdout,stdin,stderr,不能刷新普通磁盘文件,在操作普通磁盘文件的时候,\n并不作为刷新缓冲区的标志.
缓冲区满了自动刷新
正常退出的时候自动刷新.

文件缓冲区和内核缓冲区有什么区别?

C标准库中的缓冲区主要是为了减少磁盘的I/O,但这件事情是有利有弊的.
在做网络编程中,我们是不需要文件缓冲区的.

思考:
做一个cp拷贝命令,用C标准库函数实现和使用系统函数实现,哪个效率高?
这个给不出定论.APUE中对系统函数的缓冲区的大小的读写性能,可以查阅.


内核缓冲区设置:/proc/sys/net/core/,可以研究一下?
内核缓冲区有多少种?是像文件流那样每个文件流都有一个缓冲区吗?

A程序中调用C标准函数fwrite写一些内容到C标准缓冲区中,然后fwrite调用write将C标准缓冲区的内容写到了内核缓冲区中,
内核中设计了缓输出机制,守护进程定时将内核缓冲区中的内容写道磁盘中,在过程中,A程序写的内容已经出现在内核缓冲区或者磁盘上的时候,B程序都是可以读到的,内容在A程序的C标准缓冲区的时候,为A进程独有,B是无法访问的.

4.系统调用与C标准调用之间的区别

系统调用函数和库函数的区别:
从程序完成的功能来看:
函数库提供的函数通常是不需要操作系统的服务. 函数是在用户空间内执行的,除非函数涉及到I/O操作等,一般是不会切到内核态的。而系统调用是要求操作系统为用户提供某种服务,通常是涉及系统的硬件资源和一些敏感的软件资源等。

从程序执行效率来看:
当处理的数据量比较小时,函数库的函数执行效率比较好,因为函数库的函数的作法是将要处理的数据先存入缓冲区内,等到缓冲区装满了,再将数据一次写入或者读出。这种方式处理小量数据时效率比较高。但是在进行系统调用时,因为用户进程从用户模式进入系统内核模式,中间涉及了许多额外的任务的切换工作,这些操作称为上下文切换,此类的额外工作会影响系统的执行效率。那么为什么还要使用系统调用呢?这是因为,读写文件通常是大量的数据(这种大量是相对于底层驱动的系统调用所实现的数据操作单位而言),使用库函数调用可以大大减少系统调用的次数。这是因为缓冲区技术。在用户空间和内核空间,对文件操作都使用了缓冲区,当内核缓冲区写满之后或写结束之后才将内核缓冲区内容写到文件对应的硬件媒介中。

从程序的可移植性的角度来看:
对于不同的系统,系统函数的实现有很大的差别;相对于系统调用,一些库函数,如C语言的标准函数库具备较高的可移植性,在不同的系统环境下,只要做很少的修改,通常情况是不需要修改的。


从运行层面上看:
库函数是高层的,完全运行在用户空间, 为程序员提供调用真正的在幕后完成实际事务的系统调用的更方便的接口。系统调用在内核态运行并且由内核自己提供。

运行状态不同
系统调用的调用过程和被调用过程运行在不同的状态,而普通的过程调用一般运行在相同的状态。 


调用方法不同
系统调用必须通过软中断机制首先进入系统核心,然后才能转向相应的命令处理程序。普通过程调用可以直接由调用过程转向被调用过程。   

返回问题
在采用抢先式调度的系统中,当系统调用返回时,要重新进行调度分析――是否有更高优先级的任务就绪。普通的过程调用直接返回调用过程继续执行。

5.系统调用与C标准调用之间的联系

操作系统API通常都以C库的方式提供,Linux也是如此。C库提供了POSIX的绝大部分API,同时,内核提供的每个系统调用在C库中都具有相应的
封装函数。系统调用与其C库封装函数的名称常常相同,比如,read系统调用在C库中的封装函数即为read函数。
C库中的系统调用封装函数在最
终调用到相应系统调用之前,往往不做多少额外的工作。不过,某些情况下会有些例外,比如对于两个相关的系统调用truncate和truncate64,
C库中的封装函数truncate函数即需要决定它们中的哪个应该最终被调用。
当然,如下图所示,系统调用和C库
函数之间并不是一一对应的关系。可能几个不同的函数会调用到同一个系统调用,比如malloc函数和free函数都是通过brk系统调用来扩大或缩小
进程的堆栈,execl、execlp、execle、execv、execvp和execve函数都是通过execve系统调用来执行一个可执行文件。
也有可能一个函数调用多个系统调用。更有些函数并不依赖于任何系统调用,比如strcpy函数(复制字符串)和atoi函数(转换ASCII为整数),
因为它们并不需要向内核请求任何服务。

 

 

6.Linux操作系统中的系统调用接口

https://baike.baidu.com/item/unistd.h中可以看到一些系统定义,
在你的终端上,man 2 syscalls也可以看到系统调用的接口.
下面也给出一些系统调用的解释:

进程控制
fork 创建一个新进程
clone 按指定条件创建子进程
execve 运行可执行文件
exit 中止进程
_exit 立即中止当前进程
getdtablesize 进程所能打开的最大文件数
getpgid 获取指定进程组标识号
setpgid 设置指定进程组标志号
getpgrp 获取当前进程组标识号
setpgrp 设置当前进程组标志号
getpid 获取进程标识号
getppid 获取父进程标识号
getpriority 获取调度优先级
setpriority 设置调度优先级
modify_ldt 读写进程的本地描述表
nanosleep 使进程睡眠指定的时间
nice 改变分时进程的优先级
pause 挂起进程,等待信号
personality 设置进程运行域
prctl 对进程进行特定操作
ptrace 进程跟踪
sched_get_priority_max 取得静态优先级的上限
sched_get_priority_min 取得静态优先级的下限
sched_getparam 取得进程的调度参数
sched_getscheduler 取得指定进程的调度策略
sched_rr_get_interval 取得按RR算法调度的实时进程的时间片长度
sched_setparam 设置进程的调度参数
sched_setscheduler 设置指定进程的调度策略和参数
sched_yield 进程主动让出处理器,并将自己等候调度队列队尾
vfork 创建一个子进程,以供执行新程序,常与execve等同时使用
wait 等待子进程终止
wait3 参见wait
waitpid 等待指定子进程终止
wait4 参见waitpid
capget 获取进程权限
capset 设置进程权限
getsid 获取会晤标识号
setsid 设置会晤标识号




文件读写操作
fcntl 文件控制
open 打开文件
creat 创建新文件
close 关闭文件描述字
read 读文件
write 写文件
readv 从文件读入数据到缓冲数组中
writev 将缓冲数组里的数据写入文件
pread 对文件随机读
pwrite 对文件随机写
lseek 移动文件指针
_llseek 在64位地址空间里移动文件指针
dup 复制已打开的文件描述字
dup2 按指定条件复制文件描述字
flock 文件加/解锁
poll I/O多路转换
truncate 截断文件
ftruncate 参见truncate
umask 设置文件权限掩码
fsync 把文件在内存中的部分写回磁盘




文件系统操作
access 确定文件的可存取性
chdir 改变当前工作目录
fchdir 参见chdir
chmod 改变文件方式
fchmod 参见chmod
chown 改变文件的属主或用户组
fchown 参见chown
lchown 参见chown
chroot 改变根目录
stat 取文件状态信息
lstat 参见stat
fstat 参见stat
statfs 取文件系统信息
fstatfs 参见statfs
readdir 读取目录项
getdents 读取目录项
mkdir 创建目录
mknod 创建索引节点
rmdir 删除目录
rename 文件改名
link 创建链接
symlink 创建符号链接
unlink 删除链接
readlink 读符号链接的值
mount 安装文件系统
umount 卸下文件系统
ustat 取文件系统信息
utime 改变文件的访问修改时间
utimes 参见utime
quotactl 控制磁盘配额




系统控制
ioctl I/O总控制函数
_sysctl 读/写系统参数
acct 启用或禁止进程记账
getrlimit 获取系统资源上限
setrlimit 设置系统资源上限
getrusage 获取系统资源使用情况
uselib 选择要使用的二进制函数库
ioperm 设置端口I/O权限
iopl 改变进程I/O权限级别
outb 低级端口操作
reboot 重新启动
swapon 打开交换文件和设备
swapoff 关闭交换文件和设备
bdflush 控制bdflush守护进程
sysfs 取核心支持的文件系统类型
sysinfo 取得系统信息
adjtimex 调整系统时钟
alarm 设置进程的闹钟
getitimer 获取计时器值
setitimer 设置计时器值
gettimeofday 取时间和时区
settimeofday 设置时间和时区
stime 设置系统日期和时间
time 取得系统时间
times 取进程运行时间
uname 获取当前UNIX系统的名称、版本和主机等信息
vhangup 挂起当前终端
nfsservctl 对NFS守护进程进行控制
vm86 进入模拟8086模式
create_module 创建可装载的模块项
delete_module 删除可装载的模块项
init_module 初始化模块
query_module 查询模块信息
*get_kernel_syms 取得核心符号,已被query_module代替




内存管理
brk 改变数据段空间的分配
sbrk 参见brk
mlock 内存页面加锁
munlock 内存页面解锁
mlockall 调用进程所有内存页面加锁
munlockall 调用进程所有内存页面解锁
mmap 映射虚拟内存页
munmap 去除内存页映射
mremap 重新映射虚拟内存地址
msync 将映射内存中的数据写回磁盘
mprotect 设置内存映像保护
getpagesize 获取页面大小
sync 将内存缓冲区数据写回硬盘
cacheflush 将指定缓冲区中的内容写回磁盘




网络
getdomainname 取域名
setdomainname 设置域名
gethostid 获取主机标识号
sethostid 设置主机标识号
gethostname 获取本主机名称
sethostname 设置主机名称




Socket 套接字
socketcall socket系统调用
socket 建立socket
bind 绑定socket到端口
connect 连接远程主机
accept 响应socket连接请求
send 通过socket发送信息
sendto 发送UDP信息
sendmsg 参见send
recv 通过socket接收信息
recvfrom 接收UDP信息
recvmsg 参见recv
listen 监听socket端口
select 对多路同步I/O进行轮询
shutdown 关闭socket上的连接
getsockname 取得本地socket名字
getpeername 获取通信对方的socket名字
getsockopt 取端口设置
setsockopt 设置端口参数
sendfile 在文件或端口间传输数据
socketpair 创建一对已联接的无名socket




用户管理
getuid 获取用户标识号
setuid 设置用户标志号
getgid 获取组标识号
setgid 设置组标志号
getegid 获取有效组标识号
setegid 设置有效组标识号
geteuid 获取有效用户标识号
seteuid 设置有效用户标识号
setregid 分别设置真实和有效的的组标识号
setreuid 分别设置真实和有效的用户标识号
getresgid 分别获取真实的,有效的和保存过的组标识号
setresgid 分别设置真实的,有效的和保存过的组标识号
getresuid 分别获取真实的,有效的和保存过的用户标识号
setresuid 分别设置真实的,有效的和保存过的用户标识号
setfsgid 设置文件系统检查时使用的组标识号
setfsuid 设置文件系统检查时使用的用户标识号
getgroups 获取后补组标志清单
setgroups 设置后补组标志清单




进程间通信
ipc 进程间通信总控制调用




sigaction 设置对指定信号的处理方法
sigprocmask 根据参数对信号集中的信号执行阻塞/解除阻塞等操作
sigpending 为指定的被阻塞信号设置队列
sigsuspend 挂起进程等待特定信号
signal 参见signal
kill 向进程或进程组发信号
*sigblock 向被阻塞信号掩码中添加信号,已被sigprocmask代替
*siggetmask 取得现有阻塞信号掩码,已被sigprocmask代替
*sigsetmask 用给定信号掩码替换现有阻塞信号掩码,已被sigprocmask代替
*sigmask 将给定的信号转化为掩码,已被sigprocmask代替
*sigpause 作用同sigsuspend,已被sigsuspend代替
sigvec 为兼容BSD而设的信号处理函数,作用类似sigaction
ssetmask ANSI C的信号处理函数,作用类似sigaction




消息
msgctl 消息控制操作
msgget 获取消息队列
msgsnd 发消息
msgrcv 取消息




管道
pipe 创建管道




信号量
semctl 信号量控制
semget 获取一组信号量
semop 信号量操作




共享内存
shmctl 控制共享内存
shmget 获取共享内存
shmat 连接共享内存
shmdt 拆卸共享内存

7.C标准函数的一些说明

<assert.h>	包含断言宏,被用来在程序的调试版本中帮助检测逻辑错误以及其他类型的bug。
<complex.h>	一组操作复数的函数。
<ctype.h>	定义了一组函数,用来根据类型来给字符分类,或者进行大小写转换,而不关心所使用的字符集(通常是ASCII或其扩展字符集,也有EBCDIC)。
<errno.h>	用来测试由库函数报的错误代码。
<fenv.h>	定义了一组用来控制浮点数环境的函数。
<float.h>	Defines macro constants specifying the implementation-specific properties of the 浮点数 library.
<inttypes.h>	Defines exact width integer types.
<iso646.h>	Defines several macros that are equivalent to some of the operators in C. For programming in ISO 646 variant character sets.
<limits.h>	Defines macro constants specifying the implementation-specific properties of theinteger types.
<locale.h>	定义C语言本地化函数.
<math.h>	定义C语言数学函数。
<setjmp.h>	定义了宏setjmp和longjmp,在非局部跳转的时候使用。
<signal.h>	定义C语言信号处理函数。
<stdalign.h>	For querying and specifying the data structure alignment of objects.
<stdarg.h>	For accessing a varying number of arguments passed to functions.
<stdatomic.h>	For atomic operations on data shared between threads.
<stdbool.h>	Defines a boolean data type.
<stddef.h>	Defines several useful types and macros.
<stdint.h>	Defines exact width integer types.
<stdio.h>	Defines core input and output functions
<stdlib.h>	Defines numeric conversion functions, pseudo-random numbers generation functions, dynamicmemory allocation, process control functions
<stdnoreturn.h>	For specifying non-returning functions.
<string.h>	定义C语言字符串处理函数
<tgmath.h>	Defines type-generic mathematical functions.
<threads.h>	Defines functions for managing multiple threads as well as mutexes and condition variables.
<time.h>	Defines date and time handling functions
<uchar.h>	Types and functions for manipulating Unicode characters.
<wchar.h>	Defines wide string handling functions.
<wctype.h>	Defines set of functions used to classify wide characters by their types or to convert between upper and lower case

8.参考文章

https://blog.csdn.net/skyflying2012/article/details/10044343?biz_id=102&utm_term=C%E6%A0%87%E5%87%86%E5%87%BD%E6%95%B0%E4%B8%8E%E7%B3%BB%E7%BB%9F%E5%87%BD%E6%95%B0%E7%9A%84%E5%8C%BA%E5%88%AB&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-7-10044343&spm=1018.2118.3001.4187

 

 

 

 

 

 

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值