函数上的 C++ extern 关键字。为什么不只包含头文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2604202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ extern keyword on functions. Why no just include the header file?
提问by user199421
If I understand it correctly this means
如果我理解正确,这意味着
extern void foo();
that the function foo is declared in another translation unit.
函数 foo 在另一个翻译单元中声明。
1) Why not just #include the header in which this function is declared?
1) 为什么不只是 #include 声明这个函数的头文件?
2) How does the linker know where to look for function at linking time?
2) 链接器如何知道在链接时去哪里寻找函数?
edit: Maybe I should clarify that the above declaration is then followed by using the function
编辑:也许我应该澄清一下上面的声明,然后使用该函数
foo();
It is never defined in this translation unit.
它从未在此翻译单元中定义。
采纳答案by Brian Neal
1) It may not have a header file. But yes, in general, for large projects, you should have a header file if multiple translation units are going to use that function (don't repeat yourself).
1) 它可能没有头文件。但是是的,一般来说,对于大型项目,如果多个翻译单元要使用该功能,您应该有一个头文件(不要重复自己)。
2) The linker searches through all the object files and libraries it was told about to find functions and other symbols.
2) 链接器搜索它被告知要查找函数和其他符号的所有目标文件和库。
回答by goedson
As others have already stated, the extern
keyword is used to state the name (a variable or function) has external linkage, meaning the name refers to the same object in the entire program. Also, this is the default for variables and functions defined at the file scope, so this usage is superfluous.
正如其他人已经说过的那样,extern
关键字用于声明名称(变量或函数)具有外部链接,这意味着名称在整个程序中指代同一个对象。此外,这是在文件范围内定义的变量和函数的默认值,因此这种用法是多余的。
There's another use of the extern keyword that goes like this:
extern 关键字的另一种用法是这样的:
extern "C" void foo();
This means the function foo
will be linked using the C conventions for linkage (maybe because this is a function defined in a C library or is a function intended to be called by C programs).
这意味着函数foo
将使用 C 链接约定进行链接(可能是因为这是在 C 库中定义的函数,或者是打算由 C 程序调用的函数)。
回答by AnT
No, this means that function foo
is declared with external linkage. External linkage means that name foo
refers to the same function in the entire program. Where the function is defined does not matter. It can be defined in this translation unit. It can be defined in other translation unit.
不,这意味着函数foo
是用外部链接声明的。外部链接是指名称foo
在整个程序中引用同一个函数。函数在哪里定义并不重要。它可以在这个翻译单元中定义。它可以在其他翻译单元中定义。
Using extern
keyword as shown in your example is superfluous. Functions always have external linkage by default. The above is 100% equivalent to just
使用extern
示例中所示的关键字是多余的。默认情况下,函数始终具有外部链接。以上是 100% 等价于
void foo();
As for the linker, when the linker links the program together it simply looks everywhere. It looks through all definitions until it finds the definition for foo
.
至于链接器,当链接器将程序链接在一起时,它看起来无处不在。它查看所有定义,直到找到 的定义foo
。
回答by Hans Passant
It already means that without the extern keyword. Functions have external linkage by default, unless you declare them static.
这已经意味着没有 extern 关键字。默认情况下,函数具有外部链接,除非您将它们声明为静态。
Using function prototypes is okay but it is easy get it wrong. The linker error you'll get isn't that easy to diagnose when you redefine the function implementation. The linker doesn't know where to look, it is your job to give it an object file that contains the function definition to keep it happy.
使用函数原型没问题,但很容易出错。当您重新定义函数实现时,您将获得的链接器错误并不容易诊断。链接器不知道去哪里寻找,你的工作是给它一个包含函数定义的目标文件以保持它满意。
回答by BjoernD
1) I don't know why I'd need this for a function. Maybe someone else can step in.
1)我不知道为什么我需要这个功能。也许其他人可以介入。
2) The linker determines this by going through all object files and checking the symbols inside each object file. I assume that depending on your linker, the exact search order might vary.
2) 链接器通过遍历所有目标文件并检查每个目标文件中的符号来确定这一点。我假设根据您的链接器,确切的搜索顺序可能会有所不同。
For GNU binutils' ld all object files and libraries that appear in the linker command line after the object containing the missing symbol are searched from left to right and the first found symbol is picked.
对于 GNU binutils 的 ld,在从左到右搜索包含丢失符号的对象并选择第一个找到的符号之后,链接器命令行中出现的所有对象文件和库。
Example 1:
示例 1:
- a.o -- uses foo(), bar()
- liba -- provides bar()
- libb -- provides foo()
- ao -- 使用 foo(), bar()
- liba -- 提供 bar()
- libb -- 提供 foo()
$> ld a.o -la -lb
$> ld ao -la -lb
will result in a.o being searched for undefined symbols. Thereafter ld will go through the libs from left to right to search for these symbols and will find bar in liba and foo in libb.
将导致 ao 被搜索未定义的符号。此后 ld 将从左到右遍历 libs 以搜索这些符号,并会在 liba 中找到 bar 并在 libb 中找到 foo。
This may lead to strange problems upon circular dependencies:
这可能会导致循环依赖的奇怪问题:
Example 2:
示例 2:
- a.o -- uses bar()
- liba -- provides bar(), uses foo()
- libb -- provides foo(), uses bar()
- ao -- 使用 bar()
- liba -- 提供 bar(),使用 foo()
- libb -- 提供 foo(),使用 bar()
Now, there is a circular dependency between liba and libb and linking will fail:
现在,liba 和 libb 之间存在循环依赖关系,链接将失败:
$> ld a.o -la -lb
$> ld ao -la -lb
because when searching through the undefined symbols in libb, ld will determine that there is no other lib to the right of -lbthat provides this symbol. This may be fixed in at least two ways:
因为在 libb 中搜索未定义的符号时,ld 将确定-lb 右侧没有其他 lib提供此符号。这至少可以通过两种方式解决:
1) link liba twice: $> ld a.o -la -lb -la
1)链接liba两次:$> ld ao -la -lb -la
2) use ld's grouping feature $> ld a.o --start-group -la -lb --end-group
2) 使用 ld 的分组功能 $> ld ao --start-group -la -lb --end-group
In case 2), the grouping tells ld to search through all symbols in all libs belonging to this group.
在情况 2) 中,分组告诉 ld 搜索属于该组的所有库中的所有符号。