如何避免重复包含头文件

时间:2011-10-24 19:40:18

标签: c++ macros declaration header-files definition

我有以下代码:

#ifndef GOOGLESET_PHP_H
#define GOOGLESET_PHP_H 
zend_class_entry *googleset_ce;
#endif /* GOOGLESET_PHP_H */

由于某些原因,如果我将此头文件包含在多个cpp文件中,编译器会喊我不止一次声明googleset_ce。上面的条件宏不应该足以避免这种情况吗?

6 个答案:

答案 0 :(得分:7)

您需要使用extern关键字:

#ifndef GOOGLESET_PHP_H
#define GOOGLESET_PHP_H

extern zend_class_entry * googleset_ce;

#endif // GOOGLESET_PHP_H

否则,编译器会认为您在包含此标头的每个文件中声明该变量。

这是全球变数不受欢迎的一个原因。

答案 1 :(得分:5)

是的,但您只是声明一次每个编译单元

包含警卫,只确保每个使用它的.cpp声明一次。

因此,如果A.h中包含B.himpl.cpp包含A.h,则impl.cpp仅包含第一次。

在您的情况下,您将包含保护宏的值定义为静态指针变量。因此即使impl2.cpp仅包含一次,myClass* getInstance() { static myClass instance; return &instance; } 包含相同的文件也会包含它们,因此您的静态变量在链接时将具有重复的定义

如果你坚持使用静态变量(正如托马斯所说,它通常是糟糕的设计),最好将它们包装在一个函数中;

static

这稍微好一点,因为它确保变量是真正的全局变量,某些体系结构(如darwin)的每个动态库都有 myClass** getGlobalRef() { static myClass* val; return &val; } //and you set it at run-time, avoiding static-initialization happening before main * getGlobalRef() = new myClass(); 个变量,而不是每个进程,因此可能导致混乱的行为/可移植性

此外,更相关的是,静态初始化总是在main之前发生,并且不保证顺序。对于静态函数变量,变量是“按需”初始化的,因此不受初始化排序问题的影响

初始化全局指针:

{{1}}

答案 2 :(得分:1)

请注意,它是链接器错误,而不是编译器错误。当链接器尝试将所有*.o文件(包括头文件)的目标文件(*.cpp)放在一起时,会得到一个多重定义的符号。

您可能会使用extern关键字解决问题,使符号唯一。并在一个(只有一个).cpp文件中将其声明为其他地方。

答案 3 :(得分:1)

而不是使用“ #ifndef GOOGLESET_PHP_H

             #define GOOGLESET_PHP_H 

            #endif /* GOOGLESET_PHP_H */" 

您可以使用

           #pragma once

答案 4 :(得分:0)

如果标头包含在几个.c / .cpp文件中,那么它确实可能在多个.obj文件中声明。 您必须将其封装在命名空间或类中,因此不会将其视为包含它的每个.cpp文件的全局变量。

答案 5 :(得分:0)

lurscher有答案。如果你想在.cpp文件中共享相同的全局变量,一种方法是在你的一个.cpp文件中全局声明它,然后在头文件中将其声明为extern。

例如:

main.cpp
zend_class_entry *googleset_ce = NULL;

googleset.h
#ifndef GOOGLESET_PHP_H
#define GOOGLESET_PHP_H
extern zend_class_entry *googleset_ce;
#endif /* GOOGLESET_PHP_H */