c语言标准库

2019-07-13 06:38发布

标准库(Standard Library)是C语言重要的一部分,不过学习C语言这么长时间,都没有细致的了解过标准库到底中包含哪些内容,这几天打算来仔细看看这部分内容。 C语言标准库有各种不同的实现,比如最著名的glibc, 用于嵌入式Linux的uClibc,还有ARM公司的自己的C语言标准库及精简版的MicroLib等。不同标准库的实现并不相同,而且提供的函数也不完全相同,不过有一个它们都支持的最小子集,这也就是最典型的C语言标准库。 这个C语言标准库中一共包含15个头文件,粗略的按常用程度排序列举如下: Header File Content 输入和输出 最常用的一些系统函数 字符串处理 数学函数 字符类测试 时间和日期 可变参数列表 信号 断言 非局部跳转 定义错误代码 一些常数、类型和变量 本土化 浮点数运算 定义整数数据类型的取值范围
本文总结的是不完整的C标准库,仅列举一些常用且最重要的部分。

time.h

日期和时间操作。需要特别注意的是,书中使用的time_t时间戳标准是从1900年1月1日午夜开始的,这与目前广泛使用的UNIX时间戳不一样,也和Glibc的实现不一样,书中是通过_TBIAS这个宏定义偏置量来解决这个问题的,为了简单起见,此处对此进行了改写,忽略了偏置问题,直接将其修改为与UNIX时间戳一样。

使用方法

通常使用time(NULL)获取一个time_t类型的UNIX时间戳,这一般是一个32位整数(signed int),指的是从1970年1月1日午夜至今的秒数,大约可以表示到2038年。如果要获取更精确的时间,可使用clock()函数。 其余函数用于在几种不同数据结构间进行转换,根据需要选取即可,其中tm类型的定义一般是这样的: 1 2 3 4 5 6 7 8 9 10 11 struct tm { int tm_sec; /* [0, 60], 1 leap second */ int tm_min; /* [0, 59] */ int tm_hour; /* [0, 23] */ int tm_mday; /* [1, 31] */ int tm_mon; /* [0, 11] */ int tm_year; /* Years since 1900 */ int tm_wday; /* [0, 6], Sunday, Monday... */ int tm_yday; /* [0, 365], days since January 1th */ int tm_isdst; /* 夏令时标志,无效则为0 */ } 需要注意的是,以上只是time_t的最小实现,实际Glibc 2.23版本的代码中除了上述成员外还添加了其它字段。tm_year是从1900年开始的,并不是和UNIX时间戳相同的1970年。

实现方法

time()clock()函数是依赖于具体实现的,此处不作分析。 difftime()函数返回两个时间戳之间的差值,考虑到time_t可能会被定义为无符号整数,故需要先比较二者的大小: 1 2 3 double difftime(time_t t1, time_t t0) { return (t0 <= t1 ? (double)(t1 - t0) : -(double)(t0 - t1)); } tmtime_t间的转换函数是中的重点,这里主要来看一下gmtime()mktime()的实现方法。下列代码在书中给出的代码基础上进行了些改写,主要是做了些精简,没有考虑夏令时等问题。虽然以下两段代码比Glibc中的实现要简单得多,不过经测试完全可以正常使用。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 static const short lmos[] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; static const short mos[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; #define MONTAB(year) ((year & 0x03) == 2 ? lmos : mos) struct tm * gmtime(time_t * timer) { static struct tm ts; int year; int days; int secs; secs = *timer; days = secs / 86400; // 获取天数 ts.tm_wday = (days + 4) % 7; // 1970年1月1日是星期四 int dDay; /* days / 365 先求出year的初步估计,因为闰年的存在不一定准确(可能会多1年) */ /* (year + 1) / 4 求出因闰年多出来的天数 */ /* days与year年初的天数比较,若days小于它,说明year估计有误,需要减去1年 */ for (year = days / 365; days < (dDay = (year + 1) / 4 + 365 * year);) year--; days -= dDay; // 将days变成1年中的天数 ts.tm_year = year + 70; // tm_year是从1900年开始的 ts.tm_yday = days; // 总天数减去年初的天数 /* 从最后一个月开始,逐步向前寻找正确的月份,pm[mon]得到月初的天数 */ int mon; const short * pm = MONTAB(year); int tmp = (year & 0x03) == 2; for (mon = 11; days < pm[mon]; mon--); ts.tm_mon = mon; ts.tm_mday = days - pm[mon] +