【C】 06 - 标准库概述

  任何程序都会有一些通用的功能需求,对这些需求的实现组成了库。它可以提高程序的复用性、健壮性和可移植性,这也是模块化设计的体现。C规范定义了一些通用接口库,这里只作概述性介绍,具体细节当然还是要查阅规范。

  为了提高效率,C的很多库函数会同时有一个宏定义的版本,所以传递参数时尽量使用没有副作用的表达式,以免发生错误。若不想使用宏版本的函数,可以采用三个方法:(1)先undef宏;(2)函数名用括号括起来;(3)不include头文件。

// method 1
#include <stdlib.h>
#undef atoi
atoi("123");

// method 2
#include <stdlib.h>
(atoi)("123");

// method 3
extern int atoi(const char*);
atoi("123");

  输入输出库<stdio.h>包含对文件的操作、对流的控制、输入输出。C的所有读写对象被称为流,它的所有信息包含在结构体FILE里,包含buffer、位置信息等。系统有3个类型为FILE*的表达式(stdin、stdout、stderr)指向预定义的流,分别是scanf、printf、assert的默认流。库中对文件的操作包括删除、重命名、打开、关闭、buffer设置等。对流的控制包括刷新、位置获取和设置、错误处理等。输入输出包括直接输入输出、字符和字符串的输入输出、格式化输入输出等,相对应的宽字符输入输出在<wchar.h>中定义。标准库对buffer边界的检查不是很严格,如需更安全的接口,请查看ISO/IEC TR 24731。以printf为例,格式化输出提供了度量类型的可控格式输出。scanf的格式比printf简单,不作介绍,仅需注意其中空白仅起分割作用。每个格式的形式为%[flags][width][.precision][length]type,方括号为可选,具体意义如下表所示。参数传递时会先做整型提升、float转为double、指针转为void*,length和type共同决定最终输出的类型,而不是原始数据的类型。

flag -  左对齐, 默认右对齐
+  显示符号, 默认仅显示负号
空格  不显示符号的正数符号位用空格
#  8/16进制显示前缀, 浮点数总显示小数点
0  整数和浮点前导0填充, 若左对齐或整数有精度则不填充
width 正整数, *  显示的最小宽度, *表示最小宽度由参数决定
precision 正整数, 空  整数的最少数字, g/G的最多有效位, 其它浮点数的小数位数, 为空表示0
length hh, h, l, ll, j, z, t  整数分别为char/short/long/long long/intmax_t/size_t/ptrdiff_t, n为相应指针, lc为wint_t, ls为wchar_t
L  浮点数为long double
type d, i, o, u, x, X  整数, d/i为有符号整数, o/u/x/X为8/10/16进制无符号整数
f, F, e, E, g, G, a, A  浮点数, f/F为10进制浮点, e/E为10进制科学记数法, g/G为前两者较短者, a/A为16进制科学记数法
c, s  c为字符, s为字符串
p  指针
n  向整型指针参数写入已打印的字符数
%  %

  可变参数库<stdarg.h>旧名<varargs.h>,提供了一些宏获取隐式参数。函数参数的压栈顺序是基于实现的,所以编译器也要负责可变参数的管理。参数序列的信息的地址存放在va_list(指针)里,它通过va_start从参数中获取,或者用va_copy拷贝得来。va_arg从列表头部获取某个类型的参数,取完后从列表中删除。va_clean彻底释放列表信息。

// interfaces of <stdarg.h>
void va_start(va_list ap, paraN);
void va_copy(va_list dst, va_list src);
type va_arg(va_list ap, type);
void va_end(va_list ap);


// example
#include <stdarg.h>
#include <stdio.h>

void fun(int n, ...)
{
    va_list va, copy;
    int a;

    va_start(va, n);
    va_copy(copy, va);
    a = va_arg(va, int);
    va_end(va);
    va_end(copy);
}

  通用函数库<stdlib.h>提供了非常多的常用接口,它原本也是标准库的大本营。包含字符串转为数、随机数生成、动态内存管理、系统控制和调用、排序查找算法、整数的绝对值和除法、宽字符和多字节字符的转换等。通用宏定义<stddef.h>包含一些常用宏定义,包含ptrdiff_t、size_t、wchar_t、NULL、offsetof、max_align_t等。时间库<time.h>包含了时间和日期的获取和格式化打印,本地化库<local.h>可以将C配置成符合各地区习惯的书写风格,默认在初始化时设置为setlocal(LC_ALL,"C")。

// some interfaces in <stdlib.h>
int atoi(const char* nptr);
double atof(const char* nptr);
int rand(void);
void srand(unsigned int seed);
void* malloc(size_t size);
void* realloc(void* ptr, size_t size);
_Noreturn void abort(void);
int system(const char* string);
void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
int abs(int j);
div_t div(int numer, int denom);
int mbtowc(wchar_t* restrict pwc, const char* restrict s, size_t n);

  范围库<limits.h>定义了各类整型的取值范围,整数类型库<stdint.h>定义了各种长度要求的整型及其取值范围。整数类型库<inttypes.h>包含<stdint.h>,另外还有为各种整型在格式化输入输出定义了格式宏,以及这些整型的对应的通用库(<stdlib.h>)。浮点库<float.h>定义平台浮点表示的具体细节,包括各个域的范围等。浮点环境库<fenv.h>包括浮点运算环境的获取和配置,以及当前浮点运算的状态和异常信息等。

// some macros in <limits.h>
#define CHAR_BIT     8
#define SCHAR_MIN    -128
#define INT_MAX      (-2147483647 - 1)

// some macros in <stdint.h>
#define int32_t      int
#define intmax_t     long long
#define INT32_MAX    INT_MAX

// some macros in <inttypes.h>
#include <stdint.h>
#define PRId64 "lld"
intmax_t imaxabs(intmax_t j);
intmax_t strtoimax(const char* restrict nptr, char** restrict endptr, int base);

  数学函数库<math.h>定义了各种浮点数的数学函数,复数函数库<complex.h>定义了复数相关的宏以及复数的数学函数,<tgmath.h>包含了前两者,并为相同的函数使用了统一的宏(名称和中<math.h>一样)。

  字符类型库<ctype.h>和宽字符类型库<wctype.h>提供了接口判断字符的类型,还可以进行大小写转换。字符串库<string.h>提供了对字符串(内存段)的操作,包括复制、连接、查找等。宽字符库<wchar.h>包含各种函数的宽字符版本,包括格式化输入输出、字符串操作、时间显示、宽字符与单字符的转换等。unicode库<uchar.h>包括对unicode的操作和转换,符号库<iso646.h>为iso_646中没有的符号提供了单词表示,比如and表示&&。

// some interfaces in <ctype.h>
int isdigit(int c);
int islower(int c);
int toupper(int c);

// some interfaces in <string.h>
void* memcpy(void* restrict s1, const void* restrict s2, size_t n);
char* strcpy(char* restrict s1, const char* restrict s2);
char* strcat(char* restrict s1, const char* restrict s2);
int memcmp(const void* s1, const void* s2, size_t n);
char* strstr(const char* s1, const char* s2);

  长跳转库<setjmp.h>提供了函数间直接跳转的接口,用于快速回到旧的执行点。jmp_buf是个数组类型,它保存了跳转的必要信息。setjmp保存当前点,longjmp跳转到某个时间点。setjmp返回0表示是从setjmp返回的,否则是从longjmp跳转的。信号库<signal.h>提供了向系统注册信号回调函数和发起信号的接口,检查库<assert.h>在运行或编译时检查条件并报错,错误号库<errno.h>中定义的全局变量记录了上一次出错的编号。

#include <setjmp.h>
jmp_buf buf;

void f(void) {g();}
void g(void) {longjmp(buf, 1);}
int main (void)
{
    if (0 == setjmp(buf)) f();    // from setjmp
    else {}                       // from longjmp
}

  库<stdbool.h><stdalign.h><stdnoreturn.h>为新加的关键字定义了全小写的宏。库<threads.h><stdatomic.h>提供了线程和原子操作相关的宏和接口,相应内容在这里已被全部忽略(没仔细看,也没看懂),请参考规范相应内容(包括关键字_Thread_local和_Atomic的使用)。

 


【全篇完】

posted on 2014-08-30 07:12  卞爱华  阅读(1018)  评论(3编辑  收藏  举报

导航