This question already has an answer here:
这个问题已经有了答案:
- Why aren't my include guards preventing recursive inclusion and multiple symbol definitions? 1 answer
- 为什么我的include不能防止递归包含和多个符号定义?1回答
The linker reports duplicate symbol on this:
链接器报告重复的符号:
#ifndef testttt
#define testttt
void anything(){
std::cout<<"hellooooooo";
}
#endif
Because it is inside the include guards, I would expect that this function is only defined once. But apparently not.
因为它在include保护中,所以我希望这个函数只定义一次。但显然不是。
I know I can put the word static
in front of it and then it will work (which I still find ironic, since static is supposed to give it internal linkage, yet the function can be used from multiple cpp files).
我知道我可以把单词static放在它的前面,然后它就会工作(我仍然觉得这很讽刺,因为static应该给它提供内部链接,但是这个函数可以从多个cpp文件中使用)。
So I guess my two-part question is: 1) Why do the include guards not prevent multiple definitions of this function like they do for other header items, and 2) Why does the static
word resolve this when static is supposed to prevent names from visibility in other translation units? I add it, and I can actually call this function from anywhere that includes this header file.
所以我猜我的问题有两部分:1)为什么include警卫不能像对其他标题项那样防止这个函数的多个定义,2)为什么静态词可以解决这个问题,而静态词应该在其他翻译单元中阻止名称的可见性?我添加它,我可以从任何包含这个头文件的地方调用这个函数。
3 个解决方案
#1
49
"1) Why do the include guards not prevent multiple definitions of this function like they do for other header items"
“1)为什么include保护不像其他标题项那样防止这个函数的多个定义?”
Because each translation unit (i.e. .cpp file) is processed separately and goes through the same conditional. Translation units won't share the preprocessor definitions encountered by other translation units. This means that all the translation units that will process that header will include a definition for that function. Of course, the linker will then complain that the same function has multiple definitions.
因为每个翻译单元(例如。cpp文件)都是单独处理的,并且经过相同的条件。翻译单元不会共享其他翻译单元遇到的预处理器定义。这意味着处理该头的所有翻译单元都将包含该函数的定义。当然,链接器会抱怨同一个函数有多个定义。
"2) Why does the static word resolve this when static is supposed to prevent names from visibility in other translation units?"
“2)为什么静态字要解决这个问题,而静态字被认为是为了防止其他翻译单位的名称可见性?”
Because the static
keyword makes a private copy of that function for each translation unit.
因为静态关键字为每个翻译单元创建该函数的私有副本。
If you want that function to be defined in a shared header, however, you should rather mark it as inline
, which will solve your problem and will make the preprocessor guards unnecessary.
但是,如果希望在共享头中定义该函数,则应该将其标记为内联,这将解决您的问题,并使预处理器保护变得不必要。
#2
42
Why do the include guards not prevent multiple definitions of this function like they do for other header items?
为什么include不能防止这个函数的多个定义?
The process of creating an executable from a C++ program consists of three stages:
从c++程序创建可执行文件的过程包括三个阶段:
- Preprocessing
- 预处理
- Compilation &
- 编译和
- Linking
- 链接
Preprocessing: the preprocessor directives like macros etc are replaced during this stage.
Compilation is converting the source code in to object code by checking for language semantics.
Linking is to link all the generated object code together to form an executable.
预处理:在此阶段将替换诸如宏等预处理指令。编译通过检查语言语义将源代码转换为目标代码。链接是将所有生成的对象代码链接在一起,形成可执行文件。
Header guards prevent the contents of the header to be included multiple times in the same translation unit during preprocessing. They do not prevent the contents to be included in different translation units. When you include this header file in different translation units, each of these units will have a definition of this function.
The compiler compiles each translation unit separately to produce a separate object file(.o), each of those .o files will have an copy of this function definition. When the linker tries to link to the function definition at time of generating the .exe
it finds multiple definitions of the same functions, thereby causing confusion as to which one to link to. To avoid this problem the standard defines a rule known as the One defintion rule(ODR), which forbids multiple definitions of the same entity.
As you see including the function definition in the header file and including that header file in multiple translation units violates the ODR.
The usual way to do this is to provide the declaration in the header file and the definition in one and only one source file.
在预处理过程中,头保护防止在同一翻译单元中多次包含头的内容。他们不阻止内容被包括在不同的翻译单位。当您将这个头文件包含在不同的转换单元中时,每个单元都会有这个函数的定义。编译器分别编译每个翻译单元以生成一个单独的对象文件(.o),每个文件都有一个这个函数定义的副本。当链接器试图在生成.exe时链接到函数定义时,它会发现相同函数的多个定义,从而导致连接到哪个函数的混淆。为了避免这个问题,标准定义了一个规则,称为一个定义规则(ODR),它禁止对同一实体的多个定义。如您所见,在头文件中包含函数定义并在多个转换单元中包含头文件违反了ODR。通常的方法是在头文件中提供声明,在一个源文件中提供定义。
Why does the static word resolve this when static is supposed to prevent names from visibility in other translation units?
为什么静态字会在静态时解决这个问题,因为它会阻止其他翻译单元的名称的可见性?
When you add the keyword static
to the function each translation unit will have its own copy of the function. By default functions have external linkage but static
forces the function to have an internal linkage. Thus the definition is not visible to different translation units. Each instance of such a function is treated as a separate function(address of each function is different) and each instance of these functions have their own copies of static local variables & string literals. Note that this increases the size of your executable considerably.
当您向函数中添加关键字static时,每个翻译单元都有自己的函数副本。缺省情况下,函数具有外部链接,但静态强制函数具有内部链接。因此,对于不同的翻译单位,定义是不可见的。这样一个函数的每个实例都被视为一个单独的函数(每个函数的地址不同),并且这些函数的每个实例都有自己的静态局部变量和字符串文本的副本。注意,这大大增加了可执行文件的大小。
If you want to include the function definition in a header file. There are 3 ways to do it:
如果您想在头文件中包含函数定义。有三种方法:
- Mark the function as
inline
or - 将函数标记为内联或
- Mark the function as
static
or - 将函数标记为静态或。
- Put the function in an unnamed namespace.
- 将函数放在一个未命名的命名空间中。
Note that #1
and #2
do the same as mentioned in second answer above.
With #3
the standard relaxes the ODR for inline functions and allows each translation unit to have its own definition(provided all definitions are same).
注意#1和#2所做的与上面第二个答案中提到的一样。使用#3,标准放宽了内联函数的ODR,并允许每个翻译单元有自己的定义(前提是所有的定义都是相同的)。
So if you really want to put a function definition in header #1
is the right way to do it.
所以如果你真的想在header #1中添加一个函数定义的话,这是正确的方法。
#3
5
1) Why do the include guards not prevent multiple definitions of this function like they do for other header items,
1)为什么包含的警卫不像其他标题项一样阻止这个函数的多个定义,
Include guards prevent from multiple inclusion of the header in the same translation unit. It does not, however, prevent from multiple definitions : if the header is included in multiple translation unit, then there will be multiple definition error, because the function is defined in each translation unit, and since it has external linkage, all translation unit can see the definition from all other translation units. To prevent this error, you only have to provide the declaration in the header, and provide the definition in ONE .cpp
file.
包含保护,防止在同一翻译单元中包含标题。然而,它不会阻止来自多个定义:如果标题中包含多个翻译单元,然后将会有多个定义错误,因为每一个翻译单元中定义的函数,因为它有外部链接,所有翻译单元的定义可以看到其他所有翻译单元。为了避免这个错误,您只需在header中提供声明,并在一个.cpp文件中提供定义。
Read about One Definition Rule (ODR) and External Linkage.
阅读一个定义规则(ODR)和外部链接。
2) Why does the static word resolve this when static is supposed to prevent names from visibility in other translation units?
2)为什么静态字要解决这个问题,而静态字要防止其他翻译单位的名称可见性?
Because static
makes the function internal to each translation unit.That is what internal linkage means: other translation unit cannot see the definition.
因为静态使功能成为每个翻译单元的内部。这就是内部链接的含义:其他翻译单位看不到这个定义。
#1
49
"1) Why do the include guards not prevent multiple definitions of this function like they do for other header items"
“1)为什么include保护不像其他标题项那样防止这个函数的多个定义?”
Because each translation unit (i.e. .cpp file) is processed separately and goes through the same conditional. Translation units won't share the preprocessor definitions encountered by other translation units. This means that all the translation units that will process that header will include a definition for that function. Of course, the linker will then complain that the same function has multiple definitions.
因为每个翻译单元(例如。cpp文件)都是单独处理的,并且经过相同的条件。翻译单元不会共享其他翻译单元遇到的预处理器定义。这意味着处理该头的所有翻译单元都将包含该函数的定义。当然,链接器会抱怨同一个函数有多个定义。
"2) Why does the static word resolve this when static is supposed to prevent names from visibility in other translation units?"
“2)为什么静态字要解决这个问题,而静态字被认为是为了防止其他翻译单位的名称可见性?”
Because the static
keyword makes a private copy of that function for each translation unit.
因为静态关键字为每个翻译单元创建该函数的私有副本。
If you want that function to be defined in a shared header, however, you should rather mark it as inline
, which will solve your problem and will make the preprocessor guards unnecessary.
但是,如果希望在共享头中定义该函数,则应该将其标记为内联,这将解决您的问题,并使预处理器保护变得不必要。
#2
42
Why do the include guards not prevent multiple definitions of this function like they do for other header items?
为什么include不能防止这个函数的多个定义?
The process of creating an executable from a C++ program consists of three stages:
从c++程序创建可执行文件的过程包括三个阶段:
- Preprocessing
- 预处理
- Compilation &
- 编译和
- Linking
- 链接
Preprocessing: the preprocessor directives like macros etc are replaced during this stage.
Compilation is converting the source code in to object code by checking for language semantics.
Linking is to link all the generated object code together to form an executable.
预处理:在此阶段将替换诸如宏等预处理指令。编译通过检查语言语义将源代码转换为目标代码。链接是将所有生成的对象代码链接在一起,形成可执行文件。
Header guards prevent the contents of the header to be included multiple times in the same translation unit during preprocessing. They do not prevent the contents to be included in different translation units. When you include this header file in different translation units, each of these units will have a definition of this function.
The compiler compiles each translation unit separately to produce a separate object file(.o), each of those .o files will have an copy of this function definition. When the linker tries to link to the function definition at time of generating the .exe
it finds multiple definitions of the same functions, thereby causing confusion as to which one to link to. To avoid this problem the standard defines a rule known as the One defintion rule(ODR), which forbids multiple definitions of the same entity.
As you see including the function definition in the header file and including that header file in multiple translation units violates the ODR.
The usual way to do this is to provide the declaration in the header file and the definition in one and only one source file.
在预处理过程中,头保护防止在同一翻译单元中多次包含头的内容。他们不阻止内容被包括在不同的翻译单位。当您将这个头文件包含在不同的转换单元中时,每个单元都会有这个函数的定义。编译器分别编译每个翻译单元以生成一个单独的对象文件(.o),每个文件都有一个这个函数定义的副本。当链接器试图在生成.exe时链接到函数定义时,它会发现相同函数的多个定义,从而导致连接到哪个函数的混淆。为了避免这个问题,标准定义了一个规则,称为一个定义规则(ODR),它禁止对同一实体的多个定义。如您所见,在头文件中包含函数定义并在多个转换单元中包含头文件违反了ODR。通常的方法是在头文件中提供声明,在一个源文件中提供定义。
Why does the static word resolve this when static is supposed to prevent names from visibility in other translation units?
为什么静态字会在静态时解决这个问题,因为它会阻止其他翻译单元的名称的可见性?
When you add the keyword static
to the function each translation unit will have its own copy of the function. By default functions have external linkage but static
forces the function to have an internal linkage. Thus the definition is not visible to different translation units. Each instance of such a function is treated as a separate function(address of each function is different) and each instance of these functions have their own copies of static local variables & string literals. Note that this increases the size of your executable considerably.
当您向函数中添加关键字static时,每个翻译单元都有自己的函数副本。缺省情况下,函数具有外部链接,但静态强制函数具有内部链接。因此,对于不同的翻译单位,定义是不可见的。这样一个函数的每个实例都被视为一个单独的函数(每个函数的地址不同),并且这些函数的每个实例都有自己的静态局部变量和字符串文本的副本。注意,这大大增加了可执行文件的大小。
If you want to include the function definition in a header file. There are 3 ways to do it:
如果您想在头文件中包含函数定义。有三种方法:
- Mark the function as
inline
or - 将函数标记为内联或
- Mark the function as
static
or - 将函数标记为静态或。
- Put the function in an unnamed namespace.
- 将函数放在一个未命名的命名空间中。
Note that #1
and #2
do the same as mentioned in second answer above.
With #3
the standard relaxes the ODR for inline functions and allows each translation unit to have its own definition(provided all definitions are same).
注意#1和#2所做的与上面第二个答案中提到的一样。使用#3,标准放宽了内联函数的ODR,并允许每个翻译单元有自己的定义(前提是所有的定义都是相同的)。
So if you really want to put a function definition in header #1
is the right way to do it.
所以如果你真的想在header #1中添加一个函数定义的话,这是正确的方法。
#3
5
1) Why do the include guards not prevent multiple definitions of this function like they do for other header items,
1)为什么包含的警卫不像其他标题项一样阻止这个函数的多个定义,
Include guards prevent from multiple inclusion of the header in the same translation unit. It does not, however, prevent from multiple definitions : if the header is included in multiple translation unit, then there will be multiple definition error, because the function is defined in each translation unit, and since it has external linkage, all translation unit can see the definition from all other translation units. To prevent this error, you only have to provide the declaration in the header, and provide the definition in ONE .cpp
file.
包含保护,防止在同一翻译单元中包含标题。然而,它不会阻止来自多个定义:如果标题中包含多个翻译单元,然后将会有多个定义错误,因为每一个翻译单元中定义的函数,因为它有外部链接,所有翻译单元的定义可以看到其他所有翻译单元。为了避免这个错误,您只需在header中提供声明,并在一个.cpp文件中提供定义。
Read about One Definition Rule (ODR) and External Linkage.
阅读一个定义规则(ODR)和外部链接。
2) Why does the static word resolve this when static is supposed to prevent names from visibility in other translation units?
2)为什么静态字要解决这个问题,而静态字要防止其他翻译单位的名称可见性?
Because static
makes the function internal to each translation unit.That is what internal linkage means: other translation unit cannot see the definition.
因为静态使功能成为每个翻译单元的内部。这就是内部链接的含义:其他翻译单位看不到这个定义。