标准库(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;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
}
需要注意的是,以上只是
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));
}
tm
与
time_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;
int dDay;
for (year = days / 365; days < (dDay = (year + 1) / 4 + 365 * year);)
year--;
days -= dDay;
ts.tm_year = year + 70;
ts.tm_yday = days;
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] +