Point 4
通用指针void *
显然您知道void *是指向任何对象的通用指针。这一点给我们带来很大的方便。考虑下面的例子:
typedef struct CLISTLINK{
void *pvData;
struct CLISTLINK* pre;
struct CLISTLINK* next;
}CLISTLINK;
(一个简单的双向动态链表的链节点类型)
注意到pvData,一个指向数据的通用指针。这意味这该链表是通用链表,它的数据对象类型无限制。但它的“通用性”并不代表它是优雅的实现,该例子主要说明void *的使用,无意讨论哪种实现的优劣。具体实现时您要记住pvData的原类型,以便可以做显式转化来使用数据对象。
转化的一种形式:
(
(YourDataType*)pvData
)
->YourDataMember
。
再看一个例子:
BOOL CMP ( void* _a, void* _b )
{
return ((YourDataType*)_a)->_aMember == ((YourDataType*)_b)->_bMember;
}
可能您已经注意到,如何进行
YourDataType*
到
void *
的转化?可以隐式进行转化,即
pvData = &YourData
,等价于
pvData = (void *)&YourData
。
Point 5 static
变量
Static
说明适用于外部变量与函数,用于把这些对象的作用域限定为被编译源文件的剩余部分。考虑下面的例子:
//-------------------command.h------------
static void SaveCmdExplain(HCMDMSG hCmd, char *szCmd);
//body of command.h
//-----------------------------------------------
//---------------------command.c-----------
#include “command.h”
static void SaveCmdExplain(HCMDMSG hCmd, char *szCmd)
{
//Body of SaveCmdExplain
}
//body of command.c
//---------------------------------------------------
该声明及定义将
SaveCmdExplain
限制于编译单位
command.h
以及
command.h
的实现文件
command.c
内使用。
再考虑下面的例子:
char *StringToLower(char *str)
{
static char szStr[ PATH_MAX_LEN + FILE_NAME_MAX_LEN + 1 ];
//body of StringToLower
return szStr;
}
(该函数将字符串
str
转换为小写字符串,返回转换结果的首地址)
注意到
szStr
,它被定义为静态字符串数组。我们称
szStr
为内部静态变量,它像自动变量一样局部于某一特定的函数内,只能在该函数中使用,但与自动变量不同的是,不管其所在函数是否被调用,它都一直存在,而不像自动变量那样,随着所在函数的调用与退出而存在与消失。换而言之,内部静态变量在某一特定函数中使用但一直占据存储空间。这正是我们想要的结果,
StringToLower
转换的结果(
szStr
)必须保留,只有内部静态变量及动态内存分配能提供实现。考虑到动态内存分配涉及对内存的管理,忘记对其回收后会造成内存泄露,故使用自动回收的内部静态变量。