libc、glib、glibc简介
2019-07-21 17:47:56 阿炯

glibc和libc都是Linux下的C函数库:libc是Linux下的ANSI C函数库,glibc是Linux下的GUN C函数库。

glib是用C写的一些工具,即C的工具库,和libc/glibc没有关系。GLib是一个跨平台的、用C语言编写的五个底层库的集合,为GNOME所使用。GLib起初是GTK+的一部分,但到了GTK+第二版,开发者决定把跟图形界面无关的代码分开,这些代码于是就组装成了GLib。因为GLib具有跨平台特性,所以用它编写的程序可以无需进行大的修改就可以在其他程序上编译和运行。它提供了多种高级的数据结构,如内存块、双向和单向链表、哈希表、动态字符串以及字符串工具(例如词法分析器,字符串切分等)、动态数组,平衡二叉树、n-叉树、键值存储、关系和元组,还有带有缓存的内存管理。Glib还实现了线程相关的函数、多线程编程以及相关的工具,例如原始变量访问,互斥锁,异步队列,安全内存池,消息传递和日志,钩子函数和计时器,同时消息传递还包含了字节序转换和IO channel。

GLib由五个库组成:
GObject –对象系统,包括类型系统GType
Glib
GModule
GThread
GIO


glibc是linux下面c标准库的实现,即GNU C Library,即GNU旗下的C标准库,后来逐渐成为了Linux的标准C库,而Linux下原来的标准C库Linux libc逐渐不再被维护

GNU C库(英语:GNU C Library,常简称为glibc)是一种按照LGPL许可协议发布的,自由的,公开源代码的,方便从网络下载的C的编译程序。GNU C运行期库,是一种C函数库,是程序运行时使用到的一些API集合,它们一般是已预先编译好,以二进制代码形式存在Linux类系统中,GNU C运行期库通常作为GNU C编译程序的一个部分发布。Glibc最初是自由软件基金会(FSF)为其GNU操作系统所写,但当前最主要的应用是配合Linux内核,成为GNU/Linux操作系统一个重要的组成部分。

glibc在/lib(64)目录下的.so文件为libc.so.6。

查看当前系统的glibc版本的两种方法:
# ls -lh /lib64/libc.so.6
lrwxrwxrwx 1 root root 12 11月 17  2015 /lib64/libc.so.6 -> libc-2.22.so

# ldd --version
ldd (GNU libc) 2.22
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

这两种方法都可以看到当前系统的glibc的版本是2.22。

虽然 Linux + glibc 是最常见的组合,但是 glibc 并不和 Linux 绑定,反之亦然。glibc 可以运行在 Linux、Hurd 内核上,还有一个运行在 FreeBSD 内核上的非官方版本。Linux 内核可以和 glibc、musl、uclibc、bionic 等 C 库搭配。Linux 编译过程不直接依赖 glibc。Linux 内核用到的如 strcpy 之类的 C 库函数,是内核自己实现的,在 lib/ 和 arch/$ARCH/lib/ 目录下面。

在Linux平台上最广泛使用的C函数库是glibc,其中包括C标准库的实现,也包括所有系统函数。几乎所有C程序都要调用glibc的库函数,所以glibc是Linux平台C程序运行的基础。glibc提供一组头文件和一组库文件,最基本、最常用的C标准库函数和系统函数在libc.so库文件中,几乎所有C程序的运行都依赖于libc.so,有些做数学计算的C程序依赖于libm.so,多线程的C程序依赖于libpthread.so。通常在称libc时专指libc.so这个库文件,而说glibc时指的是glibc提供的所有库文件。glibc并不是Linux平台唯一的基础C函数库,也有他人在开发别的C函数库,比如适用于嵌入式系统的uClibc等。


C标准、C运行库和glibc

C标准:主要由两部分组成,一部分描述C的语法,另一部分描述C标准库(描述了一些C标准函数的原型,但是不提供实现)。

C标准库定义了一组标准头文件,每个头文件中包含一些相关的函数、变量、类型声明和宏定义。

常见的C标准就是ANSI C;美国国家标准协会制定;为了提高C语言的开发效率,C标准定义了一系列常用的函数,称为C标准库函数。
应用程序开发者可以包含这些标准函数的头文件,来调用这些C标准函数,来开发应用,这样就可以屏蔽平台的差异;

C运行库:
C标准库函数的实现留给了各个系统平台;这个实现就是C运行时库(C Run Time Libray) ,简称CRT;其是和平台相关的,即和操作系统相关的;C运行库从某种程度上来讲是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库,又称为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运行库等,它可将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++运行时库。


C 标准函数库(C standard library,缩写:libc)是在C语言程序设计中,所有符合标准的头文件(header file)的集合,以及常用的函数库实现程序(如 I/O 输入输出和字符串控制)。与COBOL、Fortran 和 PL/I等编程语言不同,在 C 语言的工作任务里不会包含嵌入的关键字,所以几乎所有的 C 语言程序都是由标准函数库的函数来建立的。

每一个函数的名称与特性会被写成一个文件,也被称为头文件,但是实际的函数实现是被分存到函数库文件里。头文件的命名和领域是很常见的,但是函数库的组织架构也会因为不同的编译器而有所不同。标准函数库通常会随附在编译器上。因为 C 编译器常会提供一些额外的非 ANSI C 函数功能,所以某个随附在特定编译器上的标准函数库,对其他不同的编译器来说,是不兼容的。

大多数 C 标准函数库设计得很好。有些少部分会为了商业优势和利益,把某些旧函数视同错误或提出警告。字符串输入函数 gets() 及 scanf() 读取字符串输入的使用是很多缓存溢出的原因,大多数的程序设计指南会建议避免使用。另一个较为奇特的函数是 strtok(),它原本是作为早期的词法分析用途,但是它非常容易出错(fragile),而且很难使用。

ANSI C共包括15个头文件。1995年,Normative Addendum 1(NA1)批准了3个头文件(iso646.h、wchar.h和wctype.h)增加到C标准函数库中。C99标准增加了6个头文件(complex.h、fenv.h、inttypes.h、stdbool.h、stdint.h和tgmath.h)。C11标准中又新增了5个头文件(stdalign.h、stdatomic.h、stdnoreturn.h、threads.h和uchar.h)。至此,C标准函数库共有29个头文件:
名字源自描述
<assert.h> 包含断言,被用来在程序的调试版本中帮助检测逻辑错误以及其他类型的bug。
<complex.h>C99一组操作复数的函数。
<ctype.h> 定义了一组函数,用来根据类型来给字符分类,或者进行大小写转换,而不关心所使用的字符集(通常是ASCII或其扩展字符集,也有EBCDIC)。
<errno.h> 用来测试由库函数报的错误代码。
<fenv.h>C99定义了一组用来控制浮点数环境的函数。
<float.h> 定义了用于浮点数库特定实现的宏常量。
<inttypes.h>C99定义精确的宽度整数类型。
<iso646.h>NA1定义几个等效于C中某些运算符的宏。用于使用ISO 646变体字符集进行编程。
<limits.h> 定义了用于整数库特定实现属性的宏常量。
<locale.h> 定义C语言本地化函数。
<math.h> 定义C语言数学函数。
<setjmp.h> 定义了宏setjmplongjmp,在非局部跳转的时候使用。
<signal.h> 定义C语言信号处理函数。
<stdalign.h>C11用于查询和指定对象的数据结构对齐方式。
<stdarg.h> 用于查询和指定对象的数据结构对齐方式。
<stdatomic.h>C11用于查询和指定对象的数据结构对齐方式。
<stdbool.h>C99定义布尔数据类型。
<stddef.h> 定义了几个常见的类型与宏。
<stdint.h>C99定义精确的宽度整数类型。
<stdio.h> 定义输入输出函数。
<stdlib.h> 定义数值转换函数,伪随机数生成函数,动态内存分配函数,过程控制函数。
<stdnoreturn.h>C11用于指定非返回函数。
<string.h> 定义C语言字符串处理函数。
<tgmath.h>C99定义类型通用数学函数。
<threads.h>C11定义用于管理多个线程以及互斥体和条件变量的函数。
<time.h> 定义日期和时间处理函数。
<uchar.h>C11用于操作Unicode字符的类型和函数。
<wchar.h>NA1定义宽字符串处理函数。
<wctype.h>NA1定义一组函数,用于按类型对宽字符进行分类或在大小写之间进行转换。



该文章最后由 于 2024-10-21 10:28:15 更新,目前是第 3 版。