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)必须保留,只有内部静态变量及动态内存分配能提供实现。考虑到动态内存分配涉及对内存的管理,忘记对其回收后会造成内存泄露,故使用自动回收的内部静态变量。