当我们在做12864液晶的字库时,常常将一个汉字取模后,保存到一个数组中,如在zimo.h中,有:
char zimo[]={ /*-- 文字: 格 20--*/ /*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/ 0x10,0x80,0x10,0x80,0x11,0xF8,0xFD,0x08,0x12,0x90,0x34,0x50,0x38,0x20,0x54,0xD8, 0x57,0x06,0x91,0xF8,0x11,0x08,0x11,0x08,0x11,0x08,0x11,0x08,0x11,0xF8,0x11,0x08};
由于该处对数组zimo[]进行了初始化,因此此处是数组的定义,而不是声明!
当几个不同的源文件分别包含这个.h文件时,编译就会出现重复定义的错误,一般的解决办法有如下两种:
方法1:规范模块化
在我的前一篇文章《C代码与工程的规范》,已经介绍了关于模块化的文件组织,在这里,我们可以将该数组在一个.c文件中进行定义:
/* zimo.c */ char zimo[32]={ /*-- 文字: 格 20--*/ /*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/ 0x10,0x80,0x10,0x80,0x11,0xF8,0xFD,0x08,0x12,0x90,0x34,0x50,0x38,0x20,0x54,0xD8, 0x57,0x06,0x91,0xF8,0x11,0x08,0x11,0x08,0x11,0x08,0x11,0x08,0x11,0xF8,0x11,0x08};
然后为该.c文件配置一个.h文件,对该数组进行全局性声明,内容如下:
/* zimo.h */ extern char zimo[32];
这样我们在使用该数组时,只需要包含zimo.h,就不会出现重复定义的错误;
方法2:利用static进行声明;
如果MCU系统的静态存储区较大,可以使用static定义该数组,此时只使用一个.h文件即可。但是这个方法个人不推荐!
在zimo.h中,定义数组如下:
/* zimo.h */ static char zimo[32]={ /*-- 文字: 格 20--*/ /*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/ 0x10,0x80,0x10,0x80,0x11,0xF8,0xFD,0x08,0x12,0x90,0x34,0x50,0x38,0x20,0x54,0xD8, 0x57,0x06,0x91,0xF8,0x11,0x08,0x11,0x08,0x11,0x08,0x11,0x08,0x11,0xF8,0x11,0x08};
在.h文件中,出现static关键字意味着什么呢?
我们知道,static关键字的作用之一是声明变量为本地变量,当A.c中,包含了zimo.h时,就相当于在A.c中定义了一个static型的数组,暂且称之为T1,它的作用范围仅限于A.c;
同时,当B.c也包含了zimo.h时,也相当于在B.c中定义了一个static型的数组,称它为T2,它的作用范围仅限于B.c;
两个数组T1、T2虽然重名,都叫zimo[],但是由于static的修饰,它们是互不影响的,等同于在内存空间中开辟了两块空间,分别用于保存T1和T2。这样就解决了重复定义的问题。但是弊端十分明显,就是包含了N次zimo.h,这个数组就新定义了N次,就浪费了N倍的存储空间。同时,在.h文件中出现实质性的定义,也不符合模块化编程的指导思想。
另附:这里附上我曾经看过的一篇文章,《在头文件中使用static意味着什么》,现将内容修改和整理如下,可以加深对static的作用的理解。
首先,在一个头文件中,用static定义一个变量:
/* Header.h */ static int g_int = 3;
其次,新建两个源文件,都包含“Header.h”:
/* Source1.c */ #include <stdio.h> #include "Header.h" void Test1() { g_int = 5; printf("g_int's address in Source1.c: %d\n", &g_int); /*打印source1.c中g_int的地址*/ printf("g_int's value in Source1.c: %d\n", g_int); /*打印source1.c中g_int的值*/ }
/* Source2.c */ #include <stdio.h> #include "Header.h" void Test2() {
g_int = 3;
printf("g_int's address in Source2.c: %d\n", &g_int); /*打印source2.c中g_int的地址*/
printf("g_int's value in Source2.c: %d\n", g_int); /*打印source2.c中g_int的值*/
}
然后在main函数中,调用这两个测试函数:
1 /* Main.c */ 2 #include "Test1.h" 3 #include "Test2.h" 4 5 void main(void) 6 { 7 Test1(); 8 Test2(); 9 }
得到的输出结果如下:
可以看到,两个源文件中的g_int的地址和值都是不同的,说明它们即使同名,但它们是互不影响的完全不同的两个变量。这就是static本地化的作用。这种声明全局变量的做法十分的不科学,应该禁止使用。
作为对比,下面给出正确的使用全局变量的方法:
/* Header.h */ extern int g_int; /*全局变量的声明*/
/* Header.c */ int g_int = 0; /*全局变量的定义*/
/* Source1.c */ #include <stdio.h> #include "Header.h" void Test1() { g_int = 5; printf("g_int's address in Source1.c: %d\n", &g_int); printf("g_int's value in Source1.c: %d\n", g_int); }
/* Source2.c */ #include <stdio.h> #include "Header.h" void Test1() { g_int = 5; printf("g_int's address in Source2.c: %d\n", &g_int); printf("g_int's value in Source2.c: %d\n", g_int); }
1 /* Main.c */ 2 #include "Test1.h" 3 #include "Test2.h" 4 5 void main(void) 6 { 7 Test1(); 8 Test2(); 9 }
运行后,得到结果如下:
可见,两个源文件使用的是同一变量。