头文件包含函数体,会导致重复的定义? [英] Header file contains function body, will lead to duplicated definition?

查看:643
本文介绍了头文件包含函数体,会导致重复的定义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我做了一个简单的实验,一个带类定义和函数定义的.h文件,如下所示:

  #pragma once $ b $ class C {
public:
void f(){}
};
void g(){}

然后这个.h文件的两个用户:

  $ cat use01.cpp 
#includetestInline.h
void g01(){
G();
C obj1;
obj1.f();


$ cat use02.cpp
#includetestInline.h
int main(){
g();
C obj2;
obj2.f();
返回0;
}

我将它们一起编译并出错:

  $ g ++ use01.cpp use02.cpp 
重复符号__Z1gv in:
/ var / folders / zv / b953j0_55vldj97t0wz4qmkh0000gn / T / use01 -34f300.o
/var/folders/zv/b953j0_55vldj97t0wz4qmkh0000gn/T/use02-838e05.o
ld:体系结构x86_64的重复符号
铿锵声:错误:链接器命令失败,退出代码1(使用-v来查看调用)

看起来很奇怪:我使用了#pragma once ,仍然无法停止编译器从报告中重复定义g()(__ Z1gv as name mangling)然后我修改testInline.h-> g()定义为如:

  inline void g(){} 

好吧,它编译。是不是在C ++中使用inline关键字基本上是无用的,因为编译器会决定它是否内联一个函数?

而且,为什么C ::带有.h文件中的代码的f()不会报告重复,而C风格的函数g()呢?为什么C类不必为其f()函数添加inline,而g()必须使用inline?

希望我已经清楚地说明了我的问题。感谢您的帮助。

解决方案


我使用过#pragma once,


是的,你做到了。并且两个翻译单元中的每一个都有效地处理了头文件一次。每个人都会这样做,即使没有编译指示,因为每个翻译单元都只包含一次头文件。



#pragma once 并不意味着只将这个头文件包含在正在编译的一个翻译单元中。这意味着即使翻译单元直接或间接包含头文件两次或更多次,每个翻译单元也包含一次该头文件。因此,每个翻译单元都包含头文件,并从头文件本身定义函数/方法。由于相同的函数或方法最终由两个翻译单元定义,所以您最终在链接时重复了一次。


是不是在C ++中,inline关键字基本上是无用的,因为
编译器会决定是否内联一个函数?

的确,编译器决定函数是否实际被内联,或者不是。但是, inline 关键字指定是否处理函数定义,就像对它的每次使用逻辑内联一样,而不是实际定义的。因此,使用 inline 关键字不会导致重复的定义,因为从逻辑上讲,该函数插入到每个引用的内联中。



的确,这是否真的发生,或者编译器是否生成非内联代码,取决于编译器。但是,C ++要求函数被编译为好像它被内联;所以即使编译器决定不内联函数,它也必须采取必要的步骤来确保函数的非内联副本不会导致格式不正确的程序。


而且,为什么C :: f()与.h文件中的代码不会报告重复,

因为在类的定义中定义的类方法实际上是一个内联定义,即使没有明确指定 inline 关键字


I've done a simple experiment, a ".h" file with a class definition and a funciton definition, as below:

$cat testInline.h
#pragma once
class C{
public:
    void f(){}
};
void g(){}

Then 2 users of this .h file:

$cat use01.cpp
#include"testInline.h"
void g01(){
    g();
    C obj1;
    obj1.f();
}

$cat use02.cpp
#include"testInline.h"
int main(){
    g();
    C obj2;
    obj2.f();
    return 0;
}

I compile them together and gets an error:

$g++ use01.cpp use02.cpp
duplicate symbol __Z1gv in:
    /var/folders/zv/b953j0_55vldj97t0wz4qmkh0000gn/T/use01-34f300.o
    /var/folders/zv/b953j0_55vldj97t0wz4qmkh0000gn/T/use02-838e05.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Looks really weird: I've used "#pragma once",still I cannot stop compiler from reporting duplicated definition of g()(__Z1gv as name mangling)

Then I modified testInline.h->g() definition to be like:

inline void g(){}

Well, it compiles. Isn't it in C++ that "inline" keyword is basically useless, because compilers will decide whether it'll inline a function or not?

And,why C::f() with code in .h file doesn't report duplication, while a C-style function g() does? And why class C doesn't "have to" add "inline" for its "f()" function, while g() has to use "inline"?

Hope I've stated my question clearly. Thanks for your help.

解决方案

I've used "#pragma once",

Yes, you did. And each one of the two translation units effectively processed the header file exactly once. Each one would've done so even without the pragma, since each translation unit includes the header file just once.

#pragma once does not mean "include this header file in just one of the translation units being compiled". It means "include this header file once per translation unit, even if the translation unit directly, or indirectly, includes the header file two or more times". As such, each translation unit included the header file, and defined the functions/methods from the header file itself. Since the same function or method ended up being defined by both translation units you ended up with a duplicate at link time.

Isn't it in C++ that "inline" keyword is basically useless, because compilers will decide whether it'll inline a function or not?

It is true that the compiler decides whether the function actually gets inlined, or not. However, the inline keyword specifies whether the function definition is processed as if it were logically inlined for every use of it, and not actually defined. As such, using the inline keyword does not result in duplicate definitions since, logically, the function is inserted inline at its every reference.

It is true that Whether this actually happens, or whether the compiler produces non-inlined code, is up to the compiler. However, C++ requires that the function gets compiled "as if" it was inlined; so even if the compiler decides not to inline the function, it must take whatever steps are necessary to ensure that the duplicate non-inlined copies of the function does not result in an ill-formed program.

And,why C::f() with code in .h file doesn't report duplication,

Because a class method defines inside the definition of the class is effectively an inline definition, even if the inline keyword is not explicitly specified.

这篇关于头文件包含函数体,会导致重复的定义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆