c标准库:fwrite()
操作系统api:write() 不少书中称之为系统调用,其实是不准确的,其实际上是操作系统对外提供的接口函数,是对系统调用的封装,其中加入了汇编指令int 0x80(软中断指令),用于使进程陷入内核态,进而执行内核态中的sys_write()函数。
fwrite和write均属于glibc库函数,只不过write实现了对系统调用的封装,是广义上的系统调用,实际上的系统调用(狭义)是在内核态中实现的。
可以参考的文章
通过man syscall,
可见,glibc在syscall()的基础上,封装了架构相关的细节,使用户更加方便使用系统调用封装函数(诸如write),而不需要考虑架构相关代码。
glibc又称c运行库,是对c标准库的拓展,其包括libc.so和libm. so(数学运算)和libpthread. so(线程库)等一系列动态库和静态库(.a)文件。
c标准库函数和操作系统api位于libc.so文件中
对于c标准库和操作系统api而言,无线程创建函数,因此需要依赖glibc额外拓展的libpthread库。
引用:
C标准:
C 标准主要由两部分组成,一部分描述C的语法,另一部分描述C标准库(描述了一些C标准函数的原型,但是不提供实现)。
C标准库定义了一组标准头文件,每个头文件中包含一些相关的函数、变量、类型声明和宏定义。
常见的C标准就是ANSI C;美国国家标准协会;
为了提高C语言的开发效率,C标准定义了一系列常用的函数,称为C标准库函数。
应用程序开发者可以包含这些标准函数的头文件,来调用这些C标准函数,来开发应用,这样就可以屏蔽平台的差异;
C运行库:
C标准库函数的实现留给了各个系统平台;
这个实现就是C运行时库(C Run Time Libray) ,简称CRT;
C运行库,是和平台相关的,即和操作系统相关的;
C运行库(CRT)从某种程度上来讲是C语言的程序和不同操作系统平台之间的抽象层;//接口是统一的标准,实现由各个平台自己实现;
Linux和Windows平台下的两个主要C语言运行库分别为
glibc(GNU C Library)和MSVCRT(Microsoft Visual C Run-time)。
值得注意的是,像线程操作这样的功能并不是标准的C语言运行库的一部分,
但是glibc和MSVCRT都包含了线程操作的库函数。所以glibc和MSVCRT事实上是标准C语言运行库的超集,
它们各自对C标准库进行了一些扩展。
也就是说CRT实际上包含两部分,一部分实现是基于C标准库来的,一部分实现是根据平台自身开发的库;
某种程度上是C运行库是C标准库的一个扩展库,加了很多C标准库所没有的与平台相关的或者不相关的库接口函数。
要在一个平台上支持C语言,不仅要实现符合平台的C编译器,还要实现C标准库,这样的实现才算符合C标准。
glibc:
这里以linux系统为例进行讨论;在Linux平台上最广泛使用的C运行库是glibc,其中包括C标准库的实现,也包括所有系统函数。
几乎所有C程序都要调用glibc的库函数,所以glibc是Linux平台C程序运行的基础。
GNU C:GNU C实际上是GNU C库,又称为glibc,即c运行库;
最基本、最常用的C标准库函数和系统函数在libc.so库文件中,几乎所有C程序的运行都依赖于libc.so
有些做数学计算的C程序依赖于libm.so,
多线程的C程序依赖于libpthread.so。
libc有时时专指libc.so这个库文件,而说glibc时指的是glibc提供的所有库文件。
值得注意的是,像线程操作这样的功能并不是C标准库的一部分(也就是说C标准没有定义线程操作相关的函数原型);
但是glibc和MSVCRT(Windows系统下的C运行库)都包含了线程操作的库函数。
比如glibc有一个可选的pthread库中的pthread_create()函数可以用来创建线程;
而MSVCRT中可以使用_beginthread()函数来创建线程。
所以glibc和MSVCRT事实上是标准C语言运行库的超集,它们各自对C标准库进行了一些扩展。
glibc的发布版本主要由两部分组成,一部分是头文件,比如stdio.h、stdlib.h等,它们往往位于/usr/include;
另外一部分则是库的二进制文件部分。二进制部分主要的就是C语言标准库,它有静态和动态两个版本。
动态的标准库我们及在本书的前面章节中碰到过了,它位于/lib/libc.so.6;而静态标准库位于/usr/lib/libc.a。
事实上glibc除了C标准库之外,还有几个辅助程序运行的运行库,这几个文件可以称得上是真正的“运行库”。
它们就是/usr/lib/crt1.o、/usr/lib/crti.o和/usr/lib/crtn.o。
比如我们可以在不同的操作系统平台下使用fread来读取文件,
而事实上fread在不同的操作系统平台下的实现是不同的,
但作为运行库的使用者我们不需要关心这一点。
虽然各个平台下的C语言运行库提供了很多功能,但很多时候它们毕竟有限,
比如用户的权限控制、操作系统线程创建等都不是属于标准的C语言运行库。
于是我们不得不通过其他的办法,诸如绕过C语言运行库直接调用操作系统API或使用其他的库。
这里讲讲GNU\GCC:
GNU软件包列表:该系统的基本组成包括GNU编译器套装(GCC)、GNU的C库(glibc)、以及GNU核心工具组(coreutils)、(GDB)。
GCC原名GNU C Compiler,后来逐渐支持更多的语言编译(C++、Fortran、Pascal、Objective-C、Java、Ada、Go等),
所以变成了GNU Compiler Collection(GNU编译器套装)
GCC是GUN Compiler Collection的简称,是Linux系统上常用的编译工具。GCC工具链软件包括GCC、Binutils、C运行库等。
GCC:
GCC(GNU C Compiler)是编译工具。本文所要介绍的将C/C++语言编写的程序转换成为处理器能够执行的二进制代码的过程即由编译器完成。
Binutils:
一组二进制程序处理工具,包括:addr2line、ar、objcopy、objdump、as、ld、ldd、readelf、size等。这一组工具是开发和调试不可缺少的工具。
addr2line:用来将程序地址转换成其所对应的程序源文件及所对应的代码行,也可以得到所对应的函数。
该工具将帮助调试器在调试的过程中定位对应的源代码位置。
as:主要用于汇编。
ld:主要用于链接。
ar:主要用于创建静态库。
ldd:可以用于查看一个可执行程序依赖的共享库。
objcopy:将一种对象文件翻译成另一种格式,譬如将.bin转换成.elf、或者将.elf转换成.bin等。
objdump:主要的作用是反汇编。
readelf:显示有关ELF文件的信息
size:列出可执行文件每个部分的尺寸和总尺寸,代码段、数据段、总大小等
C运行库
C语言标准仅仅定义了C标准库函数原型,并没有提供实现。
C语言编译器通常需要一个C运行时库(C Run Time Libray,CRT)的支持。C运行时库又常简称为C运行库。
与C语言类似,C++也定义了自己的标准,同时提供相关支持库,称为C++运行时库。