在一个软件平台上使用C语言来进行软件开发,必然要使用到C函数库。然而,不同平台的差异性使得在用C语言进行软件开发时不可能使用相同的C函数库。所以,C函数库通常有着不同的版本,这些版本都与编译器有着紧密的关联,毕竟是编译器将C代码转换为了可在某一平台上执行的机器码。
C函数库尽管有着很多的版本,但是库中的接口声明却是已经经过标准化,这也就使得对于开发人员来讲,所看到的不过是“接口”,所编写的软件在一定程度上是可以使用在多个平台之上的(只需要在该平台上重新编译过)。对于C标准而言,它仅仅规定了函数的基本原型与作用,而不规定具体的实现。所以,当我们知道了一个接口需要完成的功能,自己可以去写一遍,再和不同版本的C函数库中的核对一边,到显得挺有意思。另外,还有两点是可以学习的:一是也可以看到C库的开发人员是怎么在写代码,代码规范和注释也是可以借鉴的;二是看不同的库函数实现能够了解到更多底层的知识。
C库有着“短小精悍”的美称,虽然小但是全面,基本包含了软件开发中常用的函数。不过,通常的情况是,多数软件开发中使用到的函数仅仅是C库中的另一个小部分,基于这个原因,自己仅仅对一些常用的库函数进行了整理,描述使用中需要注意的地方,重点关注一些常用函数、易错的函数。
先说标准
1999年,腾讯的IM服务开通。这一年,C标准委员会也制定出了C99标准。相对于C89标准,C99标准当中新增了诸多有趣的特性。然而,当前业界的编译器并没有对这些有趣的特性提供完全的支持,所以,C99中仅有一部分特性得到了部分编译器的支持。而具体有哪些特性被哪些编译器所支持不是本文的重点,我对于这些也没有仔细去了解过。这里只简单的介绍一些C99标准中新增的部分特性。
1)标识符长度的限制。
C89标准规定,内部标识符或者宏名的长度、外部标识符和代码行长度的最大有效值分别为31,6和509,超过无效。外部标识符(extenal sysmbol)指的就是所谓的外部接口,也即在链接阶段需要进行符号解析和重定向的这些符号。这也是当时大多数库函数名没有超过6个字符的原因,比如memcpy, strstr, strcpy(其实我们可以发现strncpy是超过的)。在C99标准中,如上的限制被提升到63、31和4095。
2)可以使用C++风格的注释。
在自己开始学习C语言的时候就知道符号//和/**/均可以用来作为注释使用,只是在看一些C++书籍时有见过“C++中应该使用//作为注释”的说法。当时也不知道背后还有这么一段经历。可以说,C99中规定的这个特性是被当前主流编译器支持得最好的,之一。
3)内联函数。
内敛函数的使用,就我目前仅万行C的编程经验来说,还没有见过在C中使用内敛函数来提高效率,有的是直接通过宏来定义一些短小的函数,规范编码风格。其中原因可能是使用的编译器当前不支持C99标准;可能是编译器支持但懒得去添加额外的编译选项来支持C99标准;或者是根本没有必要为了这么一点点的优化去使用一些稍微复杂点的特性;或者其他。到是C++中,内联函数的使用显得比较常见。
4)Restrict pointer的使用。
说实话,这个特性我真的一次没有使用过。我在stackoverflow上学习了好几个问题仍旧没有弄明白这个特性的作用。当前扩大知识面为要,先不卷入细枝抹节的棘海之中。
5)_Bool宏。
在C89中是没有bool类型的,是的,从来没有过,我们听说bool类型应该是从C++的时候开始的吧。所以,在C99定义了_Bool类型,False和True可供掉遣,并且,据说C99为了要让C与C++兼容,还提供了stdbool.h这个头文件,让你随心所欲使用true和false。
6)在代码块中任何地方进行变量的声明。
在代码块任何地方进行变量的声明,在C++中一直是支持的,并且被当作一种较好的编码风格来提倡的。但是C中不行,即便C99已经规定该特性,当前的编译器对此特性支持的不多(请注意:此处在妄下结论,请保持警惕!)。
其他还有变长数组、for循环中定义变量、long long类型、复数支持等特性,有兴趣可以去这里开始了解。如果再一直写下去就太偏题了。这里的要点其实只有一个,C99标准规定了很多有用的特性,但是当前并没有被广泛的使用到。
正当C99还没有被完全支持的时候,C1X标准已经诞生了,并且在C99之上又有一些改变。当然,对于C99当中一些没有被支持的特性,C1X将它们置为可选。