大型工程代码如何防止头文件被重复包含



如以下代码:


//vs 2012 : test.c


#include <stdio.h>
#include "test.h"

extern i;
extern void test1();
extern void test2();

int main()
{
   test1();
   printf("ok/n");
   test2();
   printf("%d/n",i);
   return 0;
}



//vs 2012 : test.h


#ifndef _TEST_H_
#define _TEST_H_

char add1[] = "www.shellbox.cn/n";
char add2[] = "www.scriptbox.cn/n";
int i = 10;
void test1();
void test2();

#endif




//vs 2012 : test1.c

--
#include <stdio.h>
#include "test.h"

extern char add1[];

void test1()
{
   printf(add1);
}




//vs 2012 : test2.c

#include<stdio.h>
#include "test.h"

extern char add2[];
extern i;

void test2()
{
   printf(add2);
   for (; i > 0; i--) 
       printf("%d-", i);
}

 大型工程代码如何防止头文件被重复包含

 错误分析:
由于工程中的每个.c文件都是独立的解释的,即使头文件有
#ifndef _TEST_H_ #define _TEST_H_ .... #enfif
在其他文件中只要包含了test.h就会独立的解释,然后每个.c文件生成独立的标示符。在编译器链接时,就会将工程中所有的符号整合在一起,由于文件中有重名变量,于是就出现了重复定义的错误。

解决方法:
在.c文件中定义变量,然后再建一个头文件(.h文件),在所有的变量声明前加上extern,注意这里不要对变量进行的初始化。然后在其他需要使用全局变量的.c文件中包含.h文件。编译器会为.c生成目标文件,然后链接时,如果该.c文件使用了全局变量,链接器就会链接到定义变量的.c文件 。

//vs 2012 : test.h

//-------------------------------

#ifndef _TEST_H_

#define _TEST_H_

 

extern int i;

extern char add1[];

extern char add2[];

 

void test1();

void test2();

 

#endif

 

 

//vs 2012 : test.c

//-------------------------------

#include <stdio.h>

#include "test.h"

 

 

int i = 10;

char add1[] = "www.shellbox.cn/n";

char add2[] = "www.scriptbox.cn/n";

extern void test1();

extern void test2();

 

int main()

{

   test1();

  printf("ok/n");

   test2();

  printf("%d/n",i);

   return 0;

}

 

//vs 2012 : test1.c

//-------------------------------

#include <stdio.h>

#include "test.h"

 

extern char add1[];

 

void test1()

{

   printf(add1);

}

 

 

//vs 2012 : test2.c

//-------------------------------

#include <stdio.h>

#include "test.h"

 

extern char add2[];

extern int i;

 

void test2()

{

   printf(add2);

   for (; i > 0;i--)

       printf("%d-",i);

}


问题扩展: 变量的声明有两种情况:

   (1) 一种是需要建立存储空间的(定义、声明)。例如:int a在声明的时候就已经建立了存储空间。 
    (2) 另一种是不需要建立存储空间的(声明)。例如:extern int a其中变量a是在别的文件中定义的。
    前者是"定义性声明(defining declaration)"或者称为"定义(definition)",而后者是"引用性声明(referncingdeclaration)"。从广义的角度来讲声明中包含着定义,但是并非所有的声明都是定义,例如:int a它既是声明,同时又是定义。然而对于extern a来讲它只是声明不是定义。一般的情况下我们常常这样叙述,把建立空间的声明称之为"定义",而把不需要建立存储空间称之为"声明"。很明显我们在这里指的声明是范围比较窄的,也就是说非定义性质的声明。