《UNIXLinux程序设计教程》一1.4 系统库

    xiaoxiao2021-04-16  225

    1.4 系统库

    系统库给应用程序提供编译好的标准函数和系统调用函数的目标代码,这些代码在连接时与应用程序的目标代码装配在一起形成一个完整的可执行程序。UNIX系统库由许多专门的库组成,如C标准库、数学库、线程库、实时库等。本书将要介绍的函数和系统调用基本上都包含在系统库的C标准库中,也有部分包含在线程库和实时库中。C标准库不仅包含了C标准规定的函数(不包括科学计算函数以及国际化和宽字符函数),而且包含了POSIX标准定义的大部分编程接口函数。当我们编译C源程序时,编译器会自动地连接C标准库。但是,如果程序中调用了其他库中的函数,则在编译时要指定连接相应的库。例如,如果程序中调用了数学库中的函数sin(),则要在编译命令中加上选项“-lm”指定连接数学库;如果程序中调用了线程库中的函数pthread_create(),则要在编译命令中加上选项“-lpthread”指定连接Pthreads线程库。如果不指定它们的话,连接程序会报未定义的函数引用错误。Linux中系统库位于/usr/lib以及其下的子目录中。下面给出关于库的使用的其他一些说明。

    1.4.1 头文件

    库由两部分组成:头文件和实际的库。头文件定义类型和宏名,并说明变量和函数;库包含这些变量和函数的定义。在C的术语中,“说明”仅仅提供函数或变量存在的信息,对于函数说明,也可能提供参数类型信息。说明的目的是为了让编译器正确地处理这些被说明变量和函数的引用。术语“定义”才实际分配变量的存储空间和确定函数的行为。为了使用库中的函数,必须保证源程序文件包含了适当的头文件,也就是说使得编译器知道这些函数的说明以便能够正确地处理对它们的引用。一旦程序被编译,连接程序将连接这些引用至库文件中提供的实际定义。头文件通过#include预处理指导命令包含于源文件中。C语言支持两种形式的指导命令,第一种是:

    #include "header"

    这种用双引号括起来的头文件一般是程序员自己写的。header可以是任意正文文件。第二种形式是:

    #include <file.h>

    这种形式用于包含系统提供的头文件,它含有系统库中函数的定义和说明,这个文件通常由系统管理员放置在一个标准位置。Linux中它们一般位于目录/usr/include以及其下的子目录中。对于标准库调用,应当使用第二种形式。有一些头文件自动地含有另外的头文件,但是,作为一种程序设计风格,应当不要依赖于这一点,最好是明显地包含库函数要求的所有头文件。第二次包含同一个头文件不会有影响。同样,当程序需要包含多个头文件时,它们的顺序可以是随意的。

    1.4.2 保留字

    保留字是系统专门保留使用权并有特定含义的名字。C标准库中所有ANSI C标准中的类型名、宏名、变量名和函数名都无条件地是保留字。所有其他的库名字,如果源程序中明显包含了定义或说明它们的头文件,则这些名字也是保留字。这样约定的原因是:1)遵循保留字的约定有助于程序的理解、修改和维护。2)可避免用户偶然重新定义被其他库函数使用了的函数。3)如果这些函数不存在被其他用户重新定义的可能性,则可方便编译器对其感兴趣的库函数调用做某些优化。有一些库函数,例如涉及可变参数的函数以及不含非局部转移的函数,实际上需要编译器做相当部分的工作。因此,在实现上,由编译器将这一部分作为语言的内建部分来处理能达到更好的效果。除了标准定义的类型名、宏名、变量名和函数名之外,UNIX系统也约定,所有以一个下划线符('_')开头的外部标识符(全局函数和变量)、所有以两个下划线符('__',注意,由于印刷的原因常常会使得两个下划线符看起来像一个长下划线符)开头或以一个下划线符后随一个大写字母开头的标识符均是保留字。这个约定使得库和头文件能够为内部目的定义函数、变量和宏名字而不会与用户程序中的名字相冲突。除此之外,关于保留字还有其他一些约定,这些约定主要是为了将来的扩充。我们在编程时应避免使用这类名字。对于头文件专用的保留字则当程序包含了这些头文件时才应避免使用它们。下面是一些头文件保留字规则的例子:以字母E后随一数字或大写字母开头的名字,保留作为错误代码名。以“is”或“to”后随一小写字母开头的名字,保留作为字符测试和转换函数名。以“LC_”后随一大写字母开头的名字,保留作为说明地区属性的宏名。所有以“f”或“l”为后缀的数学函数名字,保留用于对float和long double类型的数据进行运算的函数。以“SIG”后随一大写字母开头的名字,保留用于信号数。头文件< fcntl.h>保留以“l_”、“F_”、“O_”和“S_”为前缀的名字。头文件保留以“_MAX”为后缀的名字。头文件保留以“sa_”和“SA_”为前缀的名字。头文件保留以“st_”和“S_”为前缀的名字。头文件保留以“tms_”为前缀的名字。

    1.4.3 特征测试宏

    头文件定义了大量的符号名,这些符号名是变量名、类型名、函数名以及与系统有关的符号常数等。这些符号名中有许多是各种标准定义的,如C标准、POSIX标准等,另外一些则是具体实现定义的。在这些符号名的定义之间既有共存,也有互斥。例如,Linux系统头文件中可以看到如下定义:

    #ifdef __USE_POSIX #include <bits/posix1_lim.h> #endif #ifdef __USE_POSIX2 #include <bits/posix2_lim.h> #endif #ifdef __USE_XOPEN #include <bits/xopen_lim.h> #endif

    它根据__USE_POSIX、__USE_POSIX2和__USE_XOPEN定义与否而包含不同的限制值定义文件。这里,宏名__USE_POSIX、__USE_POSIX2和__USE_XOPEN便是特征测试宏。特征测试宏控制着编译一个源文件时头文件中有效符号名的确切集合。例如,如果我们想编译一个源文件使得它只依赖于POSIX的定义,并且不使用任何实现定义的限制值(1.8节),就必须定义_POSIX_SOURCE。当_POSIX_SOURCE有定义时,所有POSIX.1头文件都使用这个常数排斥任何实现定义的限制值符号名。特征测试宏必须用下划线符'_'开头,应用可以在头文件中定义自己的特征测试宏,同样,系统也可以定义实现专用的特征测试宏,如__USE_GNU或__USE_POSIX。另外,UNIX标准还有下面一些专用的特征测试宏,利用它们,应用可在各种标准和实现之间进行选择。_POSIX_SOURCE:POSIX定义的特征测试宏,如果有定义,只使用ANSI C和POSIX.1标准定义的符号名和函数定义。_SVID_SOURCE:SVID定义的特征测试宏,如果有定义,除使用ANSI C和POSIX.1标准定义的符号名和函数定义外,还包括由SVID派生的符号名以及函数。_XOPEN_SOURCE:X/OPEN定义的特征测试宏,如果有定义,使用POSIX和X/OPEN标准定义的符号名以及函数。其值设为500,保持与统一规范版本2一致;其值设为600,则与统一规范版本3保持一致。__STDC__:C标准定义的特征测试宏,由符合ANSI C标准的C编译程序自动定义。如果有定义,只使用ANSI C特征。特征测试宏定义必须用“#define”定义于任何包含头文件的“#include”预处理命令之前,最好将它们放在文件的最前面,仅随注释之后。例如,如果我们只希望使用POSIX.1的定义,则应当在源程序的第一行写出:

    #define _POSIX_SOURCE 1

    也可以在cc命令行中用“-D”选项定义它们:

    cc -D_POSIX_SOURCE foo.c

    这导致源程序在任何头文件被包含之前定义特征测试宏。

    相关资源:Unix/Linux 编程实践教程.PDF

    最新回复(0)