如果一个文件中的全局变量需要向其他工程文件输送,那么最简单的办法就是使用 extern 声明,类似这样:
XXX.h
typedef struct
{
T_XXXConfig tCfg; //设备配置
T_XXXInfo txxxInfo[RADIO_MAX];//设备信息
int32_t wpaID; //wpa network id
char wpaSSID[SSID_LEN]; //记录的ssid
struct nl_sock *pUsock; //netlink套接字,用于单播收发消息
struct nl_sock *pMsock; //netlink套接字,用于多播监听内核消息
}T_XXX;
extern T_XXX xxx; //对外声明全局变量
XXX.c
T_XXX xxx = {0}; //创建一个初始化的全局变量,供外部使用
貌似看起来没什么问题,但是一旦项目持续扩大,需要加入的全局信息越来越多,而且针对某些程序需要修改的仅仅只是其中的一部分而已,为此暴露出了整一个信息块就非常不安全。
再来看我写的一个项目中全局变量:
XXX_collect.h
typedef struct
{
T_macList macList; //全局mac表
int32_t baseType; //基线类型
int32_t taskCount; //AP 专用:任务计数
int32_t connectFlag; //STA专用:连接状态
}T_collect;
/* 获取全局mac表头节点 */
T_macList *getMacList(void);
/* 操作基线类型的函数集 */
int32_t getBaseType();
void setBaseType();
/* 操作任务计数的函数集 */
int32_t getTaskCount(void);
void addTask(int32_t i);
void subTask(int32_t i);
/* 操作连接状态的函数集 */
int32_t getConnectFlag();
void setConnectFlag(int32_t i);
XXX_collect.c
static T_collect collect; //收集全局需要的信息
int32_t getBaseType()
{
return collect.baseType;
}
T_macList *getMacList(void)
{
return &collect.macList;
}
int32_t getTaskCount(void)
{
return collect.taskCount;
}
void addTask(int32_t i)
{
collect.taskCount += i;
}
void subTask(int32_t i)
{
collect.taskCount -= i;
}
int32_t getConnectFlag(void)
{
return collect.connectFlag;
}
void setConnectFlag(int32_t i)
{
collect.connectFlag = i;
}
static 声明的变量不需要初始化为0,因为分配在静态区没有初始化的变量,编译器会全部初始化为0。
static 声明很重要,这么做可以保证这个变量只能被文件内部定义的函数操作;
当 static 声明函数时,该函数同样也不需要向外部声明,同时不可直接被外部调用,但是这里是为了向外部提供针对性操作全局变量的方法。
有没有发现其实就和设计模式中的接口隔离原则很像?
没错,其实我还是很喜欢把C语言当成 C with class 来编程的。
这点可以参考 Linux 设备模型源码中的 kref 的实现,对设备的使用计数,同样是维护了一个全局变量,并且也是向外提供针对性的操作方法。