[C/C++]在头文件中使用static定义变量意味着什么

文章出处:http://www.cnblogs.com/zplutor/

看到有一位同学在头文件中这么写:

1 static const wchar_t* g_str1 = …
2 static const wchar_t* g_str2 = …

这种定义变量的方式我从来没有见过,而且它还能顺利通过编译,于是我很想知道编译器是如何处理这种变量定义的。

定义全局变量时使用static,意味着该变量的作用域只限于定义它的源文件中,其它源文件不能访问。既然这种定义方式出现在头文件中,那么可以很自然地推测:包含了该头文件的所有源文件中都定义了这些变量,即该头文件被包含了多少次,这些变量就定义了多少次。

假如将上面两行代码的static去掉,编译的时候就会出现变量重定义的错误,这进一步证实了上面的推测,因为没有static的话变量的作用域是全局的,定义了两个以上的同名变量就会出现该错误。

推测终究是推测,要真正证实这个推测还要通过写代码来验证。验证的方式是:在头文件中使用static定义变量,在多个源文件中包含该头文件,然后在每个源文件中输出变量的地址,同时在一个源文件中改变变量的值并输出,在另一个源文件中也输出。如果每个源文件的输出都不同,则推测得证;否则推测是错误的。

下面是定义变量的头文件的代码:

1 //Header.h
2 #pragma once
3
4 static int g_int = 3;

接下来在另一个头文件中声明两个测试函数:

1 //Functions.h
2 #pragma once
3
4 void TestSource1();
5 void TestSource2();

分别在两个源文件中定义这两个测试函数:

 1 //Source1.cpp
 2 #include <stdio.h>
 3 #include "Header.h"
 4
 5 void TestSource1() {
 6
 7     wprintf(L"g_int‘s address in Source1.cpp: %08x\n", &g_int);
 8     g_int = 5;
 9     wprintf(L"g_int‘s value in Source1.cpp: %d\n", g_int);
10 }
1 //Source2.cpp
2 #include <stdio.h>
3 #include "Header.h"
4
5 void TestSource2() {
6
7     wprintf(L"g_int‘s address in Source2.cpp: %08x\n", &g_int);
8     wprintf(L"g_int‘s value in Source2.cpp: %d\n", g_int);
9 }

最后在main函数中调用这两个测试函数:

1 //Main.cpp
2 #include "Functions.h"
3
4 int wmain() {
5
6     TestSource1();
7     TestSource2();
8 }

运行该程序:

可以看到,虽然在代码中好像使用了相同的变量,但是实际上使用的是不同的变量,在每个源文件中都有单独的变量。所以,在头文件中定义static变量会造成变量多次定义,造成内存空间的浪费,而且也不是真正的全局变量。应该避免使用这种定义方式。

作为对比,下面使用正确的方式来定义全局变量:

1 //Header.h
2 #pragma once
3
4 extern int g_int;
 1 //Source1.cpp
 2 #include <stdio.h>
 3 #include "Header.h"
 4
 5 int g_int = 3;
 6
 7 void TestSource1() {
 8
 9     wprintf(L"g_int‘s address in Source1.cpp: %08x\n", &g_int);
10     g_int = 5;
11     wprintf(L"g_int‘s value in Source1.cpp: %d\n", g_int);
12
13 }

其它文件不变。

运行程序:

可以看到,这次两个源文件中使用的都是同一个变量。要注意的是,使用extern声明变量时不能带有初始值,否则仍然属于变量定义,会出现变量重定义的错误。

时间: 2024-08-10 23:16:11

[C/C++]在头文件中使用static定义变量意味着什么的相关文章

头文件中不可以放变量的定义

注意头文件中不可以放变量的定义!!!一般情况下头文件中只放变量的声明,因为头文件 要被其他文件包含(即#include),如果把定义放到头文件的话,就不能避免多次定义变量, C++不允许多次定义变量,一个程序中对指定变量的定义只有一次,声明可以无数次. 不过有三个例外,一下三中实体的定义也可放到头文件中 1.值在编译时就已知的const 变量的定义可以放到头文件中 如:const int num(10); 2.类的定义可以放到头文件中 3.inline 函数 4.C++11的新特性 conste

不要在头文件中写函数定义

我们都知道static声明静态函数在别的文件是不可以使用的,但是如果你将定义也写在.h文件下是不是还是这样的呢,或者说编译器会不会提示你这样是有问题的呢?结果却是将static函数的定义直接写在了file.h的头文件中,导致staic关键字失效,代码如下. //file1.h #include <iostream>using namespace std; static void fun() { cout << "static fun" << ends

c语言头文件中定义全局变量的问题

问题是这么开始的: 最近在看一个PHP的扩展源码,编译的时候的遇到一个问题: ld: 1 duplicate symbol for architecture x86_64 仔细看了一下源码,发现在头文件中 出现了全局变量的定义. 简化一下后,可以这么理解: // t1.h #ifndef T1_H #define T1_H int a = 0; #endif //------------------ //t1.c #include "t1.h" #include "t2.h&

c语言头文件中定义变量

最近在看一个PHP的扩展源码,编译的时候的遇到一个问题: ld: 1 duplicate symbol for architecture x86_64 仔细看了一下源码,发现在头文件中 出现了全局变量的定义 ZEND_DECLARE_MODULE_GLOBALS(xx) 简单开来,可以这么理解 // t1.h #ifndef T1_H #define T1_H int a = 0; #endif //------------------ //t1.c #include "t1.h" #

将函数实现放在头文件中

研究一个开源算法库,采用C++模板编程,所有函数实现都放在了头文件中,现在把模板去掉,链接时发生冲突,具体原因如下: 因为多个源文件包含了含有函数定义的头文件,在编译的时候,每个源文件都会包含一份函数定义,在链接时编译器不知道需要连接哪一份函数定义. 解决方法有三个: 1. inline关键字 可以用关键字inline修饰函数定义,例如: inline int add(int x, int y) { return x + y; } 使用inline关键字,编译器会在调用此函数的地方把函数的目标代

函数放在头文件中被多次包含的重定义问题

Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu 转载请标明来源 例如一个头文件headfile.h这样写 #pragma once bool Func (){return true;} 在这个头文件被多个地方包含的时候就会出问题,链接时报错: (FuncB报重定义) "fatal error LNK1169: 找到一个或多个多重定义的符号" 原因是,在headfile.h中定义了函数及其实现,如果被包含时,则会把函数实现放入包含的位置,被包含

能不能在头文件中定义全局变量?(转)

地址:https://blog.csdn.net/baidu_35679960/article/details/79200865 1.ANSI C标准是什么?GNU又是什么?ld是什么? ANSI C是C语言的标准规范,是国际标准化组织制定的国际标准. 虽然 ANSI C规范了C语言的实现,但是在实际情况中,各家C语言提供商都会根据平台的不同情况对ANSI C进行一定的扩展.因此可以将现实中C语言实现看作是ANSI C的一个超集.比较有代表性的例子是linux的gcc编译器.由于该编译器对ANS

[C++]关于头文件中的防卫式声明(#ifndef...#pragma once)

大家知道,我们写.h文件时,通常会加上防卫式声明,有以下两种方式: 1. 宏定义 #ifndef _FILENAME_ #define _FILENAME_ //... #endif 2. 编译器指令 #pragma once 但是,为什么头文件中需要添加这种防卫式声明呢?如果没有这样的声明,会出现怎样的问题.这里,先看一个例子. -- "Car.h",代码如下(并没有添加防卫式声明): // Car.h class Car { // ... }; -- "Person.h&

第2条:在类的头文件中尽量少引入其他头文件

@class (向前声明) #import 注意:如果在各自头文件中引入对方的头文件,则会导致“循环引用 ”. 虽然#import(而非#inculde指令)不会导致死循环,但却意味着两个类里有一个无法被正确编译.