我有以下代码:
#ifndef GOOGLESET_PHP_H
#define GOOGLESET_PHP_H
zend_class_entry *googleset_ce;
#endif /* GOOGLESET_PHP_H */
由于某些原因,如果我将此头文件包含在多个cpp文件中,编译器会喊我不止一次声明googleset_ce
。上面的条件宏不应该足以避免这种情况吗?
答案 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.h
且impl.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 */