关于头文件变量的声明和定义

本文探讨了在C/C++中头文件内变量定义与声明的区别及潜在问题,通过实例验证了变量仅能在单一源文件中定义的原则。

先说说结论吧!

在很多论坛和问问中看到这样的问题:  在头文件是否可以定义变量?今天写了一堆文件进行了验证。

结论:1.在头文件中可以定义变量,但我们一般不这样做,在C语言中,变量只能定义一次,而头文件经常被多个文件包含,

             这样的结果就是,变量被多次定义。

          2.在头文件中   int var; 是定义。 extern int var;是声明;   C++ primer  edition four ;  p67   

           3.在.c文件中,  int var; (写在所有函数外面)   是变量的定义,extern int var;才是变量的声明。

我写了几个文件进行了验证。文件结构如下(ubuntu下画图比较麻烦,我还是把Makefile文件贴出来吧。文件可下载,tar zxvf    mulifile.tar.gz 就好):

    

target:  main.o cal.o print.o var.o
        gcc -o target main.o    cal.o   print.o var.o
main.o:  main.c print.h cal.h externvar.h
        gcc -c main.c   
var.o:  var.c
        gcc -c var.c

cal.o:  cal.c cal.h
        gcc -c cal.c 

print.o: print.c  print.h
        gcc -c print.c


clear:  
        rm -f *.o

cal.c:

#include "cal.h"
extern int a;
extern int b;

int sum()
{
        return a+b;
}

cal.h:

int sum();

externvar.h:

int dd=0;//这里是变量的定义

main.c:

#include "externvar.h"
#include "cal.h"
#include "print.h"
int main()
{
        extern int a;
        extern int b;

        printA();
        printB();
        printf("sum:%d\n",sum());
}

print.c:

#include "print.h"
extern int a;
extern int b;
void printA()
{
        printf("a:%d\n",a);
}
void printB()
{
        printf("b:%d\n",b);
}

print.h:

#include <stdio.h>

//int c;//在头文件中这样写是定义
//变量只能定义一次

void printA();
void printB();

var.c:

int a=11;
int b;

根据Makefile可以看出,print.h被两次包含,一次是在main.c,一次是在print.c,如果去掉注释  int cc=21;这是个变量的定义,再make 会报多次定义的错。在externvar.h 中有着变量dd=0;的定义,但make并没有报错,因为只包含了一次(在main.c中),相当于只定义了一次,并不违反语法规则。所以得到以上结论。



在C++头文件中,变量既可以是声明也可以是定义,不过需要遵循一定的规则,以避免重复定义错误等问题。 ### 变量声明 变量声明只是告诉编译器变量的类型名称,并不为变量分配内存。常见的声明方式有: - **使用`extern`关键字**:在头文件中使用`extern`声明全局变量,表明该变量在其他地方定义。例如: ```cpp // MyHeader.h extern int a; // 声明全局变量a ``` 这样,多个`.cpp`文件包含该头文件时,不会出现重复定义的问题,因为`extern`只是声明,不是定义。在某个`.cpp`文件中需要对其进行定义: ```cpp // MySource.cpp #include "MyHeader.h" int a = 10; // 定义全局变量a ``` 这种方式适用于需要在多个翻译单元(`.cpp`文件)中共享同一个变量实例的情况,即外部链接(external linkage) [^3][^5]。 ### 变量定义 变量定义会为变量分配内存。一般情况下,不建议在头文件中直接定义变量,因为如果该头文件被多个`.cpp`文件包含,会导致重复定义错误。不过,在特定情况下可以在头文件定义变量: - **`static`关键字**:使用`static`关键字定义变量具有内部链接(internal linkage),即每个包含该头文件的翻译单元都有一个单独的实例,它们互不影响。例如: ```cpp // MyHeader.h static int a_static = 0; // 每个包含此头文件的翻译单元都有自己的a_static实例 ``` - **`const`关键字**:`const`变量默认具有内部链接,并且其值无法修改。例如: ```cpp // MyHeader.h const int a_const = 0; // 内部链接,且值不可修改 ``` - **C++17及更高版本的`inline`关键字**:可以使用`inline`关键字在头文件中直接定义变量。例如: ```cpp // MyHeader.h #pragma once #include <QColor> namespace Config { inline QColor borderColor = QColor(Qt::blue); // C++17+ 允许头文件直接定义 } ``` 这里的`borderColor`变量可以在头文件中直接定义,因为`inline`关键字允许在多个翻译单元中存在相同的定义,编译器会确保只有一个实例被使用 [^4]。 - **类内变量的特殊情况**: - **普通成员变量**:在类中声明的普通成员变量,每个类的实例都有单独的成员。例如: ```cpp // MyHeader.h struct A { int a = 0; // 每个实例A都有单独的成员a }; ``` - **静态成员变量**:类的静态成员变量所有实例共享,通常在头文件中只是声明,需要在某个`.cpp`文件中进行定义。例如: ```cpp // MyHeader.h struct A { static int b; // 仅作为变量声明 }; // MySource.cpp #include "MyHeader.h" int A::b = 0; // 定义静态成员变量b ``` - **C++17及更高版本的`inline static`**:对于类的静态成员变量,可以使用`inline static`声明形式,声明定义,不需要额外的翻译单元。例如: ```cpp // MyHeader.h struct A { inline static int c = 0; // 静态成员变量的inline声明形式,声明定义 }; ``` - **静态成员函数的内部静态变量**:相当于静态成员变量,在没有C++17支持的情况下,可变相实现不依赖翻译单元的静态成员变量。例如: ```cpp // MyHeader.h struct A { static int& get_d() { static int d = 0; return d; } }; ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值