简体   繁体   English

“内部联系”是什么意思?

[英]What does “internal linkage” mean?

In the standard it says that: 在标准中它说:

When a name has internal linkage , the entity it denotes can be referred to by names from other scopes in the same translation unit. 当名称具有内部链接时,其表示的实体可以通过同一翻译单元中其他范围的名称来引用。

and: 和:

A name having namespace scope (3.3.6) has internal linkage if it is the name of — a variable, function or function template that is explicitly declared static; 具有命名空间作用域(3.3.6)的名称具有内部链接(如果它是 - 一个显式声明为静态的变量,函数或函数模板的名称);

So consider the following code: 请考虑以下代码:

#include <stdio.h>

namespace A
{
        /* a with internal linkage now.
           Entity denoted by a will be referenced from another scope.
           This will be main() function scope in my case
        */
    static int a=5;
}

int main()
{
        int a; //declaring a for unqualified name lookup rules
    printf("%d\n",a);//-1216872448
}

I really don't understand the definitions in the standard. 我真的不明白标准中的定义。 What does it mean that: 这意味着什么:

the entity it denotes can be referred to by names from other scopes in the same translation unit. 它表示的实体可以通过同一翻译单元中其他范围的名称来引用。

A translation unit usually consists of single source file with all #include d files and results in one object file . 翻译单元通常由单个源文件和所有#include d文件组成,并生成一个目标文件

A name in namespace scope has by default external linkage , meaning you can refer that name from other translation units (with scope resolution operator or using directive). 命名空间范围名称在默认情况下外部链接 ,这意味着你可以参考这个名字从其他翻译单元(带范围解析操作或使用指令)。 But if the name is qualified with static , the linkage becomes internal , and the name can not be referred outside the translation unit in which it was defined. 但是,如果使用static限定名称,则链接将变为内部 ,并且名称不能在定义它的转换单元之外引用。

In your example you could access a if the namespace A , the name a and main method is in the same translation unit. 在您的例子,你可以访问a如果命名空间A ,名字amain方法是在同一个翻译单元。 But in main , you are declaring another variable a , which hides the a in namespace A . 但是,在main ,您声明另一个变量a ,隐藏a命名空间A and the a in main is not initialized, so when you print, it actually prints garbage value from a declared in main . a主没有初始化,所以当你打印,它实际上是从打印垃圾值a中声明main If you want to use a from A in main , use like cout<<A::a or use using namespace A; 如果你想使用aAmain ,请使用类似cout<<A::a或使用using namespace A; in the source file containing main . 在包含main的源文件中。

"Translation unit" is the technical term for the chunk of code the compiler processes at one time. “翻译单元”是编译器一次处理的代码块的技术术语。 Usually this is a .cpp source file and all of the header files it includes. 通常这是一个.cpp源文件及其包含的所有头文件。

In practice, this usually means that a translation unit gets compiled into an object file. 实际上,这通常意味着翻译单元被编译成目标文件。 This object file is not the complete program; 该目标文件不是完整的程序; it must be "linked" with other object files to make the final program. 它必须与其他目标文件“链接”才能生成最终程序。 The "linking" process is simply matching up the various functions and such that are defined in one translation unit and used in one or more others. “链接”过程简单地匹配在一个翻译单元中定义并在一个或多个其他翻译单元中使用的各种功能。

For example, your translation unit calls printf , but the definition (machine code) for printf is actually in another translation unit. 例如,您的翻译单元调用printf ,但对于定义(机器码) printf其实是另一个翻译单元。 So the linker has to know 1) where the actual definition of printf is, and 2) where in your code it's called, so it can plug the address of 1) into 2). 所以链接器必须知道1) printf的实际定义在哪里,以及2)在你的代码中调用它的位置,因此它可以将1)的地址插入2)。

printf is an example of something with external linkage; printf外部链接的一个例子; it can be linked to things external to its translation unit. 它可以链接到翻译单元外部的东西。 On the flip side, something with internal linkage can only be linked within its translation unit. 另一方面,具有内部链接的东西只能在其翻译单元内链接。 So, in your example, main can access A::a , which is declared static at the namespace level, but functions defined outside of this translation unit have no way of seeing A::a . 因此,在您的示例中, main可以访问A::a ,它在命名空间级别声明为static ,但此转换单元之外定义的函数无法看到A::a This is because the compiler omits the reference to A::a from the link table in the object file. 这是因为编译器省略了对象文件中链接表对A::a的引用。

Finally, what's happening in your example is that the a that main sees is the one it declared inside itself, which is uninitialized. 最后,你的例子中发生的事情是, main看到的是它本身声明a那个,它是未初始化的。 That's why it's printing a garbage value. 这就是它打印垃圾价值的原因。 If you changed main to: 如果您将main更改为:

int main()
{
    printf("%d\n", A::a);
}

it would print 5 . 它会打印5

the entity it denotes can be referred to by names from other scopes in the same translation unit. 它表示的实体可以通过同一翻译单元中其他范围的名称来引用。

For this to make sense, you have to understand the difference between the entity and the name. 为此,您必须了解实体和名称之间的区别。

In your main function, you are creating a new entity and giving it the name a . 在您的main函数中,您将创建一个新实体并为其命名a The name does not refer to the same entity called a that is in namespace A. It's a different entity not only because it has different linkage, but also because it is in a different namespace. 该名称不是指名称空间A中名为a的同一实体。它是一个不同的实体,不仅因为它具有不同的链接,还因为它位于不同的命名空间中。

Local variables have no linkage by default, and so they always specify a new entity. 默认情况下,局部变量没有链接,因此它们总是指定一个新实体。 For example 例如

static int a = 5; // a new entity with name `a` that has internal linkage.

int main()
{
    int a; // This is a new entity local to function main with no linkage.
           // It isn't initialized, so you have undefined behavior if you try to
           // access it.
}

In this case, you have two entities, both named a , but they refer to different entities because they are in different scopes with different linkages. 在这种情况下,您有两个名为a实体,但它们引用不同的实体,因为它们位于具有不同链接的不同范围内。

The situation the standard is referring to is like this: 标准所指的情况是这样的:

static int a = 5; // A new entity with the name `a` that has internal linkage.

void f()
{
   extern int a; // This is a new declaration for the same entity called `a` in
                 // the global scope.
}

Now you only have one entity, but you still have two names in two different scopes. 现在您只有一个实体,但在两个不同的范围内仍有两个名称。 Those two names are referring to that same single entity. 这两个名称指的是同一个实体。

This is a very tricky point. 这是一个非常棘手的问题。 Because the declaration inside f() has extern , you are saying that you want f's a to refer to an entity that is defined elsewhere. 因为里面的声明f()extern ,你说你要F公司a指在别处定义的实体。 However, since there is already a declaration for a at global scope that is declared static , it makes the a have internal linkage instead of external linkage. 然而,由于已经有一份声明, a在全球范围内被声明static ,它使a有内在联系的,而不是外部链接。

Note that there isn't much practical value for having two names for the same entity with internal linkage since you can always just use the first name instead. 请注意,对于具有内部链接的同一实体具有两个名称没有多大实际价值,因为您始终只需使用第一个名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM