| 碧海潮生's profile碧海潮生的小屋PhotosBlogLists | Help |
|
May 25 设计笔记——标准库(上)“为了问心无愧地得到报酬,你也应该真正掌握第II组 (指职业程序员必须掌握的标准库)的内容。” —— 《C and C++ Code Capsules》 日常的C代码大部分由库调用组成,甚至I/O程序如printf和scanf 都是库的一部分,而不是语言。因此,了解标准库势在必行。 1 从memmove谈起 在某个项目开发过程中,为了完成帧封装/解封装协议, 我在代码中使用了memmove函数实现数据块的搬移。 这部分代码在VC++ 6.0下运行正常, 但是当我们将这些代码移植到嵌入式系统上时,问题出现了。 可能是出于实现效率的考虑,我们的固件工程师决定自己实现memmmove。 给出的代码大致如下: void *memmove(void *dst, const void *src, size_t len) { char *det_ptr; const char *src_ptr; if (len <= 0) return dst; dst_ptr = dst; src_ptr = src; while (len--) *dst_ptr++ = *src_ptr++; return dest; } 应该说,若需要实现的是memcpy函数,那么这段代码是相当漂亮的。 但是,标准库的memmove函数说明中明确指出:该函数应能处理 当“源单元和目的单元缓冲区交迭”的情况。 而我在编码时也恰恰是因为源单元和目的单元缓冲区交迭, 才选用了这个函数,而没有采用memcpy。 于是,当用上面这样的实现代替库函数时,程序的结果就出现了错误。 当意识到这个问题时,你的第一反应可能是“难道要用malloc?!”。 答案是否定的!正确且优雅的实现应当是: void *memmove(void *dst, const void *src, size_t len) { char *dst_ptr; const char *src_ptr; if (len <= 0) return dst; dst_ptr = dst; src_ptr = src; if (dst_ptr < src_ptr) { while (len--) *dst_ptr++ = *src_ptr++; } else { dst_ptr += len; src_ptr += len; while (len--) *--dst_ptr = *--src_ptr; } return dst; } 引起这个问题的根本原因是对标准库函数的定义和行为不熟悉。 学习一门语言不光要熟悉语言本身,对开发环境提供的库函数也要有所了解。 切记,一个函数的错误实现可能导致整个项目的失败。 2 C标准库 标准C库由在15个头文件中声明的函数、类型定义和宏组成。可分为三组。 第I组:每个C程序员都应该知道的知识 <ctype.h> 字符处理 <stdio.h> 输入/输出 <stdlib.h> 复杂的工具 <string.h> 文本处理 第II组:职业程序员的工具 <assert.h> 断言支持 <limits.h> 整型系统参数 <stddef.h> 通用类型和常量 <time.h> 时间处理 第III组:需要时可以发挥大作用的工具 <errno.h> 错误检测 <float.h> 浮点型系统参数 <locale.h> 本地化 <math.h> 数学函数 <setjmp.h> 非局部跳转 <signal.h> 信号(中断)处理 <stdarg.h> 可变参数表 以下,仅对常用的四个库(ctype.h、stdlib.h、string.h和math.h)作简要说明。 3 <ctype.h> 3.1 字符测试函数 1> 函数原型均为int isxxxx(int) 2> 参数为int, 任何实参均被提升成整型 3> 只能正确处理处于[0, 127]之间的值 isalpha 'A'~'Z', 'a'~'z' isdigit '0'~'9' isxdigit '0'~'9', 'A'~'F', 'a'~'f' isalnum isalpha || isdigit islower 'a'~'z' isupper 'A'~'Z' isspace 9 '\t' (tab: 水平制表位) 10 '\n' (line feed: 换行) 11 '\v' (home: 垂直制表位) 12 '\f' (form feed: 换页) 13 '\r' (carriage return: 回车) 32 ' ' (space: 空格) isgraph 33~126 isprint isgraph || ' ' ispunct isgraph && !isalnum iscntrl 0~31, 127 3.2 字符映射函数 1> 函数原型为int toxxxx(int) 2> 对参数进行检测, 若符合范围则转换, 否则不变 int tolower(int); 'A'~'Z' ==> 'a'~'z' int toupper(int); 'a'~'z' ==> 'A'~'Z' 3.3 附测试代码 #include <stdio.h> #include <ctype.h> char (* isxx_name[]) = { "isalpha", "isdigit", "isxdigit", "isalnum", "islower", "isupper", "isspace", "isgraph", "isprint", "ispunct", "iscntrl" }; int (* isxx_list[])(int) = { isalpha, isdigit, isxdigit, isalnum, islower, isupper, isspace, isgraph, isprint, ispunct, iscntrl }; int main() { int i, k; for (i=0; i<sizeof(isxx_list)/sizeof(isxx_list[0]); i++) { printf("Testing %s\n", isxx_name[i]); for (k=0; k<128; k++) if (isxx_list[i](k)) printf("%3d %c\n", k, k); printf("\n"); } return 0; } Comments (3)
TrackbacksThe trackback URL for this entry is: http://jx-kingwei.spaces.live.com/blog/cns!F7A152EB74B9576E!1504.trak Weblogs that reference this entry
|
|
|