关于函数的外部关键字。为什么不直接包含头文件?

时间:2022-07-15 15:08:19

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.

它从未在此翻译单元中定义。

5 个解决方案

#1


26  

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)链接器搜索所有被告知要查找函数和其他符号的目标文件和库。

#2


15  

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的定义。

#3


13  

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程序调用的函数)。

#4


7  

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.

使用函数原型是可以的,但很容易弄错。重新定义函数实现时,您将获得的链接器错误并不容易诊断。链接器不知道在哪里查找,为您提供一个包含函数定义的目标文件以保持其满意是您的工作。

#5


2  

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()
  • a.o - 使用foo(),bar()
  • liba -- provides bar()
  • liba - 提供bar()
  • libb -- provides foo()
  • libb - 提供foo()

$> ld a.o -la -lb

$> ld a.o -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.

将导致a.o被搜索未定义的符号。此后ld将从左到右遍历libs以搜索这些符号,并在libb中找到bar,在libb中找到foo。

This may lead to strange problems upon circular dependencies:

这可能会导致循环依赖的奇怪问题:

Example 2:

例2:

  • a.o -- uses bar()
  • a.o - 使用bar()
  • liba -- provides bar(), uses foo()
  • liba - 提供bar(),使用foo()
  • libb -- provides foo(), uses bar()
  • 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 a.o -la -lb

because when searching through the undefined symbols in libb, ld will determine that there is no other lib to the right of -lb that 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 a.o -la -lb -la

2) use ld's grouping feature $> ld a.o --start-group -la -lb --end-group

2)使用ld的分组功能$> ld a.o --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搜索属于该组的所有库中的所有符号。

#1


26  

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)链接器搜索所有被告知要查找函数和其他符号的目标文件和库。

#2


15  

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的定义。

#3


13  

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程序调用的函数)。

#4


7  

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.

使用函数原型是可以的,但很容易弄错。重新定义函数实现时,您将获得的链接器错误并不容易诊断。链接器不知道在哪里查找,为您提供一个包含函数定义的目标文件以保持其满意是您的工作。

#5


2  

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()
  • a.o - 使用foo(),bar()
  • liba -- provides bar()
  • liba - 提供bar()
  • libb -- provides foo()
  • libb - 提供foo()

$> ld a.o -la -lb

$> ld a.o -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.

将导致a.o被搜索未定义的符号。此后ld将从左到右遍历libs以搜索这些符号,并在libb中找到bar,在libb中找到foo。

This may lead to strange problems upon circular dependencies:

这可能会导致循环依赖的奇怪问题:

Example 2:

例2:

  • a.o -- uses bar()
  • a.o - 使用bar()
  • liba -- provides bar(), uses foo()
  • liba - 提供bar(),使用foo()
  • libb -- provides foo(), uses bar()
  • 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 a.o -la -lb

because when searching through the undefined symbols in libb, ld will determine that there is no other lib to the right of -lb that 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 a.o -la -lb -la

2) use ld's grouping feature $> ld a.o --start-group -la -lb --end-group

2)使用ld的分组功能$> ld a.o --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搜索属于该组的所有库中的所有符号。