第3章 高级C数据类型
人们在设计完全傻瓜式的系统时,常犯的错误就是低估了十足傻瓜的能力。
――Douglas Adarns
3.1指针
在C程序中,指针一般用来:
构造链式数据结构;引用动态分配的数据结构;实现引用调用(call by reference)访问和迭代数据元素;传递数组参数;引用函数;作为其他值的别名;代表字符串;直接访问系统内存。
#define new(type) (type*) calloc(sizeof(sizeof(type),1)
[…]
node=new(struct codeword_entry);
用一个宏来完成数据结构的动态分配。
Static char * ccval (const struct cchar *,int);
C函数只能返回指向数组元素的指针,不能返回整个数组。因此,当函数在数组中生成结果,并返回相应的指针时,一定要确保该数组不是在函数的栈上分配的局部变量,避免出现这类问题的一种方法是将这类数组声明为static。这种做法也并非完全安全,使用全局或static局部变量的函数大多数情况下都不可重入(reentrant)。这意味着,如果这个函数的一个实例正在运行,那么程序中其他执行线程就不能再调用它。更坏的情况是,在我们的示例中,函数的结果必须在该函数再次被调用之前,保存到其他地方(例如,使用strdup调用);否则,它将被新的结果重写。
C语言不允许将函数作为参数传递给其他函数,然而,它允许传递指向函数的指针。
在阅读基于字符串的代码时,要注意区分字符指针和字符数组。
3.2结构
结构在C语言中的应用如下:
将一般作为一个整体来使用的数据元素集合到一起;从函数中返回多个数据元素;构造链式数据结构;映射数据在硬盘设备、网络链接和存储介质上的组织方式;实现抽象数据类型;以面向对象的方式编程。
Struct fxp_cb_nop{
Void * fill[2];
Volatile u_int16_t cb_status;
Volatile u_int16_t cb_command;
Volatile u_int32_t link_addr;
};
Volatile限定符(qualifier)用来标明,底层的内存字段要被程序之外的实体使用,从而,禁止编译器对这些字段执行优化,比如移除冗余引用。
结构内字段的次序依赖于所处的架构和所用的编译器,因此用结构来映射外部数据天生不可移植。
3.3共用体
C共用体(union)将共享同一个存储区域的项聚合起来。某一时刻,共享该区域的这些项中,只有一项可以访问。在C程序中共用体主要用于下述用途:
有效地利用存储空间;实现多态(polymorphism);使用不同的内部表达方式对数据进行访问。
到目前为止,共用体最常见的应用是实现多态。此处的意思就是同一个对象用于代表不同的类型。这种用途的共用体一般会潜入到包含type字段的C结构中,这个type字段表示共用体存储的数据类型,常用一个名为type的枚举类型来表示。
我们最后分析的共用体应用是将数据存入共用体的一个字段,然后访问另外的字段,以完成数据在不同内部表达方式之间的转换。尽管这种应用天生不能移植,但有些转换是能够安全执行的,其他一些情况虽然比较有用,但要依赖具体机器。
3.4动态内存分配
一般将malloc封装到执行检查malloc返回值的函数中(一般命名为xmalloc),在需要调用malloc的地方用这个函数来替代。
如果需要更多的空间,则调用C库函数realloc,将第一个参数指向的空间,调整为由函数的第二个参数指定的新大小。该函数返回一个指向调整后内存块的指针,它的地址可能和最初块的地址并不相同。原内存块中的内容被复制到新的位置。