使用C语言的一半价值在于使用其标准库函数。当然,灵活的for循环以及数组和指针之间的相似性也是C语言的重要价值。在解决实际问题时,能方便地操作字符串和文件等对象是最重要的,有些语言能出色地完成其中的一部分工作,另一些语言能出色地完成其中的另一部分工作,然而,没有几种语言能象C语言那样能出色地完成全部工作。c标准库中还缺少很多函数,例如投有图形函数,甚至没有全屏幕文本操作函数,signal机制也相当弱(见12.10),并且根本没有对多任务或使用常规内存以外的内存提供支持。尽管C标准库存在上述缺陷,但它毕竟为所有的程序都提供了一套基本功能,不管这些程序是运行在多任务、多窗口的环境下,还是运行在简单的终端上,或者是运行在一台昂贵的烤面包机上。C标准库中所缺的函数可以从其它途径获得,例如编译程序开发商和第三方的函数库都会提供一些函数,这些函数都是事实上的标准函数。然而,标准库中的函数已经为程序设计提供了一个非常坚实的基础。12.1为什么应该使用标准库函数而不要自己编写函数?标准库函数有三点好处:准确性、高效性和可移植性。准确性:编译程序的开发商通常会保证标准库函数的准确性。更重要的是。至少开发商做了全面的检测来证实其准确性,这比你所能做到的更加全面(有些昂贵的测试工具能使这项工作更加容易)。高效性:优秀的C程序员会大量使用标准库函数,而内行的编译程序开发商也知道这一点。如果开发商能提供一套出色的标准库函数,他就会在竞争中占优势。当对相互竞争的编译程序的效率进行比较时,一套出色的标准库函数将起到决定性的作用。因此,开发商比你更有动力,并且有更多的时间,去开发一套高效的标准库函数。可移植性:在软件要求不断变化的情况下,标准库函数在任何计算机上,对任何编译程序都具有同样的功能,并且表达同样的含义,因此它们是C程序员屈指可数的几种依靠之一。有趣的是,你很难找到一项关于标准库函数的最标准的信息。对于每一个函数,都需要有一个(在极少数情况下需要两个)保证能将该函数的原型提供给你的头文件(在调用任何一个函数时,都应该包含其原型,见8.2)。有趣的是什么呢?这个头文件可能并不是真正包含该函数原型的文件,在有些(非常糟糕!)情况下,甚至由编译程序手册推荐的头文件都不一定正确。对于宏定义,typedef和全局变量,同样会发生这种情况。为了找到“正确的”头文件,你可以在一份ANSI/ISOc标准的拷贝中查阅相应的函数。如果你手头没有这样一份拷贝,你可以使用表12.2。请参见:8.2为什么要使用函数原型?12.2为了定义我要使用的标准库函数,我需要使用哪些头文件?12.2为了定义我要使用的标准库函数,我需要使用哪些头文件?你需要使用ANSI/ISO标准规定的你应该使用的那些头文件,见表12.2。有趣的是,这些文件并不一定定义你要使用的函数。例如,如果你要使用宏EDOM,你的编译程序保证你能通过包含(errno.h)得到这个宏,而(errno.h)可能定义了宏EDOM,也可能只包含定义这个宏的头文件。更糟的是,编译程序的下一个版本可能会在另一个地方定义宏EDOM。因此,你不用去寻找真正定义一个函数的头文件并使用这个文件,而应该使用那个被假定为定义了该函数的头文件,这样做是肯定可行的。有几个名字在多个头文件中被定义:NULL,size_t和wchar_t。如果你需要其中一个名字的定义,可以使用任意一个定义了该名字的头文件((stddef.h是一个较好的选择,它不仅小,而且包含了常用的宏定义和类型定义)。表12.2标准库函数的头文件----------------------------------------------------------------------函数头文件----------------------------------------------------------------------abortstdlib.habsstdlib.hacosmath.hasctimetime.hasinmath.hassertassert.hatanmath.hatan2math.hatexitstdlib.hatofstdlib.hatoistdlib.hatolstdlib.hbsearchstdlib.hBUFSIZstdio.hcallocstdlib.hceilmath.hclearerrstdio.hclocktime.hCLOCKS-PER-SECtime.hclock_ttime.hcosmath.hcoshmath.hctimetime.hdifftimetime.hdivstdlib.hdiv_tstdlib.hEDOMerrno.hEOFstdio.hERANGEerrno.herrnoerrno.hexitstdlib.hEXIT_FAILUREstdlib.hEXIT_SUCCESSstdlib.hexpmath.hfabsmath.hfclosestdio.hfeofstdio.hferrorstdio.hfflushstdio.hfgetcstdio.hfgetposstdio.hfgetsstdio.hFILEstdio.hFILENAME-MAXstdio.hfloormath.hfmodmath.hfopenstdio.hFOPEN_MAXstdio.hfpos_tstdio.hfpnntfstdio.hfputcstdio.hfputsstdio.hheadstdio.hfreestdlib.hfreopenstdio.hfrexpmath.hfscanfstdio.hfseekstdio.hfsetposstdio.hftellstdio.hfwritestdio.hgetcstdio.hgetcharstdio.hgetenvstdlib.hgetsstdio.hgmtimetime.hHUGE-VALmath.h_IOFBFstdio.h_IOLBFstdio.h_IONBFstdio.hisalnumctype.hisalphactype.hiscntrlctype.hisdigitctype.hisgraphctype.hislowerctype.hisprintctype.hispunctctype.hisspacectype.hisupperctype.hisxdigitctype.hjmp_bufsetjmp.hlabsstdlib.hLC_ALLlocale.hLC_COLLATElocale.hLC_CTYPElocale.hLC_MONETARYlocale.hLC_NUMERIClocale.hLC_TIMElocale.hstructlconvlocale.hldexpmath.hldivstdlib.hldiv_tstdlib.hlocaleconvlocale.hlocaltimetime.hlogmath.hlog10math.hlongjmpsetjmp.hL_tmpnamstdio.hmallocstdlib.hmblenstdlib.hmbstowcsstdlib.hmbtowcstdlib.hMB_CUR_MAXstdlib.hmemchrstring.hmemcmpstring.hmemcpystring.hmemmovestring.hmemsetstring.hmktimetime.hmodfmath.hNDEBUGassert.hNULLlocale.h.stddef.h.stdio.h.stdlib.h.string.h.time.hoffsetofstddef.hperrorstdio.hpowmath.hprintfstdio.hptrdiff_tstddef.hputcstdio.hputcharstdio.hputsstdio.hqsortstdlib.hraisesignal.hrandstdlib.hRAND_MAXstdlib.hreallocstdlib.hremovestdio.hrenamestdio.hrewindstdio.hscanfstdio.hSEEK_CURstdio.hSEEK_ENDstdio.hSEEK_SETstdio.hsetbufstdio.hsetjmpsetjmp.hsetlocalelocale.hsetvbufstdio.hSIGABRTsignal.hSIGFPEsignal.hSIGILLsignal.hSIGINTsignal.hsignalsignal.hSIGSEGVsignal.hSIGTERMsignal.hsig_atomic_tsignal.hSIG_DFLsignal.hSIG_ERRsignal.hSIG_IGNsignal.hsinmath.hsinhmath.hsize_tstddef.h.stdlib.h.string.hsprintfstdio.hsqrtmath.hsrandstdlib.hsscanfstdio.hstderrstdio.hstdinstdio.hstdoutstdio.hstrcatstring.hstrchrstring.hstrcmpstring.hstrcollstring.hstrcpystring.hstrcspnstring.hstrerrorstring.hstrftimetime.hstrlenstring.hstrncatstring.hstrncmpstring.hstrncpystring.hstrpbrkstring.hstrrchrstring.hstrspnstring.hstrstrstring.hstrtodstdlib.hstrtokstring.hstrtolstdlib.hstrtoulstdlib.hstrxfrmstring.hsystemstblib.htanmath.htanhmath.htimetime.htime_ttime.hstructtmtime.htmpfilestdio.htmpnamstdio.hTMP_MAXstdio.htolowerctype.htoupperctype.hungetcstdio.hva_argstdarg.hva_endstdarg.hvaliststdarg.hva_startstdarg.hvfprintfstdio.hvprintfstdio.hvsprintfstdio.hwchar_tstddef.h.stdlib.hwcstombsstdlib.hwctombstdlib.h-------------------------------------------------------------------------请参见:5.12#include(file~和#include“file”有什么不同?12.1为什么应该使用标准库函数而不要自己编写函数?12.3怎样编写参数数目可变的函数?你可以利用(stdarg.h)头文件,它所定义的一些宏可以让你处理数目可变的参数。注意:这些宏以前包含在名为(varargs.h)或类似的一个头文件中。你的编译程序中可能还有这样一个文件,也可能没有;即使现在有,下一个版本中可能就没有了。因此,还是使用(stadrg.h)为好。如果对传递给c函数的参数不加约束,就没有一种可移植的方式让c函数知道它的参数的数目和类型。如果一个c函数的参数数目不定(或类型不定),就需要引入某种规则来约束它的参数。例如,printf()函数的第一个参数是一个字符串,它将指示其后都是一些什么样的参数:printf(Hello,world!\n);/*nomorearguments*/printf(%s\n,Hello,world!);/*onemorestringargument*/printf(%s,%s\n,Hello,world!);/*twomorestringarguments*/printf(%s,%d\n,Hello,42