C语言头文件中定义变量问题

本文详细介绍了C++中头文件重复包含导致变量重复定义的常见问题,并提供了有效的解决方法,包括使用宏定义和外部声明内部定义的方式。通过实践示例,解释了标准C语言和C++在处理此类问题时的不同行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上个星期回学校的时候,刚好碰到一个学弟在写程序,并且刚好碰到一个总编不过去的问题,我看了看,正好是个头文件重复包含问题,问题描述如下:

他在程序中建立了一个global.h的文件,代码如下:

#ifndef _GLOBAL_H_

#define _GLOBAL_H_

int a;

int b;

int c;

然后在其他文件代码中,有多个.cpp文件引用他,编译的时候编译器报变量重复定义。

 

其实这是个C语言的基本问题,如果学过编译原理的人就很清除问题在哪里。假设上面的头文件global.h,有三个.cpp文件,1.cpp, 2.cpp, 3.cpp都包含了这个头文件。那么在编译的时候分别生成 1.obj, 2.obj, 3.obj。在这三个obj文件中都包含变量a, b, c。那么在链接的时候你让机器怎么去分别三个a变量,三个b变量,三个c变量,那么就只好给你报个错了。

 

不过,如果是从事Linux或者以前标准C语言开发的人可能会想,我原来编程就是这么编的,怎么就没有报错。对的,有些编译器是具有这种重定义自动检测的,LinuxC编程。我目前用的编程环境是Visual studio.net 2003。我写了两个小程序测试了一下,一个是标准C程序,如下:

head1.h

#ifndef _HEADER1_H_

#define _HEADER1_H_

void print_1();

#endif

head2.h

#ifndef _HEADER2_H_

#define _HEADER2_H_

void print_2();

#endif

global.h

#ifndef _GLOBAL_H_

#define _GLOBAL_H_

int g_test;

#endif

 

head1.c

void print_1()

{

 g_test=1;

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

}

 

head2.c

void print_2()

{

 g_test=2;

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

}

main.c

void main()

{

print_1();

print_2();

}

经过测试,这种方式是对的。

然后,我写了段c++代码,程序代码和上面的一模一样,就是.c文件变成了.cpp文件。结果就报重定义的错误。

由此可见,这个问题是C++新标准。而上述标准C能够编译过,说明这种对重定义的支持是依据编译器的,但是对于编译器来说,不是必须的。所以程序员写程序最好不要用上述代码写,现在一般程序员对这个问题流行的写法是如下:

 #ifndef     _GLOBLE_H     

  #define     _GLOBLE_H     

  extern   int     a;     

  extern   int     b;     

  extern   int     c;     

  #endif     

    

  然后在其他的某个.cpp文件中定义

  int     a;     

  int     b;     

  int     c;    

但是这种写法在具有大量的变量时候,容易造成声明的头文件和变量定义的cpp文件中变量的不一致。

下面是我给出一个的解决方法。

定义一个宏,:MAIN, global.h,加入如下代码:

#ifdef MAIN

#define EXTERN    //定义变量

#else

#define EXTERN extern  //声明变量

#endif

EXTERN int a;

EXTERN int b;

EXTERN int c;

然后在你的1.cpp ,  2.cpp ,  3.cpp ,在其中的一个.cpp

#define MAIN

#include "gloabl.h"

进行定义。这样相当于对gloabl.h中的变量进行定义。

而在其他的cpp,如需要引用global.h中的变量,

#include "gloabl.h"

而不需要#define MAIN.或者将#define MAIN定义在#include "gloabl.h"的后面。这样编译的时候就会将gloabl.h中的变量作为声明来看待。

这样即使变量再多,也不会出现头文件和CPP文件中的变量不符。因为所有的变量只需在一个文件中写入。

嘿嘿,完了,不知道有没有说清楚。如果还有疑惑欢迎大家提问交流。

 

### C语言头文件定义数组时出现重定义错误的解决方案 在C语言中,头文件通常用于声明函数、变量或宏定义。如果在头文件中直接定义数组,并且该头文件个源文件包含,则可能会导致“重定义”错误。这是因为每个源文件包含头文件时,都会重新定义数组,从而违反了C语言的一次定义规则(One Definition Rule, ODR)。以下是解决此类问题的详细方法[^1]。 #### 方法一:使用`extern`关键字 为了防止头文件中的数组被定义,可以将数组声明为外部变量(external variable),并在一个单独的源文件中定义它。头文件中只需声明数组的存在,而不实际分配存储空间。例如: ```c // 头文件 header.h #ifndef HEADER_H #define HEADER_H extern int myArray[10]; // 声明数组,但不分配存储空间 #endif ``` ```c // 源文件 source.c #include "header.h" int myArray[10] = {0}; // 在一个源文件中定义数组 ``` 通过这种方式,数组的实际定义仅存在于一个源文件中,而其他文件通过`extern`关键字引用该数组,避免了重复定义问题[^1]。 #### 方法二:使用`#ifndef`保护头文件 即使使用`extern`关键字,仍需确保头文件本身不会被重复包含。为此,可以在头文件中使用包含保护机制(include guards)或`#pragma once`指令。例如: ```c // 头文件 header.h #ifndef HEADER_H #define HEADER_H extern int myArray[10]; // 声明数组 #endif ``` 或者使用`#pragma once`简化包含保护: ```c // 头文件 header.h #pragma once extern int myArray[10]; // 声明数组 ``` 这种机制可以防止头文件次包含,从而减少潜在的重复定义问题[^2]。 #### 方法三:将数组定义为静态局部变量 如果数组的作用域仅限于单个源文件,可以将其定义为静态局部变量。这样,数组只会在定义它的源文件中可见,避免了全局作用域的冲突。例如: ```c // 源文件 source.c #include "header.h" static int myArray[10] = {0}; // 定义为静态局部变量 ``` 在这种情况下,头文件中无需声明数组,因为它是特定源文件的私有数据[^1]。 #### 方法四:使用宏定义数组大小 如果数组的大小是固定的,可以通过宏定义来管理数组大小,从而提高代码的可维护性。例如: ```c // 头文件 header.h #ifndef HEADER_H #define HEADER_H #define ARRAY_SIZE 10 extern int myArray[ARRAY_SIZE]; // 声明数组 #endif ``` ```c // 源文件 source.c #include "header.h" int myArray[ARRAY_SIZE] = {0}; // 定义数组 ``` 这种方法不仅解决了重定义问题,还使数组大小易于修改和维护[^1]。 --- ### 注意事项 - 如果需要在个源文件中访问数组,推荐使用`extern`关键字结合包含保护机制。 - 如果数组仅限于单个源文件,建议将其定义为静态局部变量。 - 避免在头文件中直接定义非`const`变量,除非明确使用`inline`或`static`修饰符。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值