"internal linkage"是什么意思?

What does "internal linkage" mean?

本文关键字:意思 linkage internal 是什么      更新时间:2023-10-16

标准中说:

当一个名称具有内部链接时,它所表示的实体可以是由同一翻译单元中其他作用域的名称引用。

:

具有命名空间作用域(3.3.6)的名称具有内部链接变量、函数或函数模板的名称显式声明static;

考虑下面的代码:

#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("%dn",a);//-1216872448
}

我真的不明白标准中的定义。

是什么意思?

中它所表示的实体可以被其他作用域的名称引用相同的翻译单元。

翻译单元通常由单个源文件和所有#include d文件组成,结果为一个目标文件

命名空间作用域中的名称在默认情况下具有外部链接,这意味着您可以从其他翻译单元(使用作用域解析操作符或使用指令)引用该名称。但是,如果名称用static限定,则链接变为内部,并且该名称不能在定义它的翻译单元之外被引用。

在您的示例中,如果名称空间A,名称amain方法在相同的翻译单元中,则可以访问a。但是在main中,您声明了另一个变量a,它将a隐藏在名称空间A中。并且main中的a没有初始化,所以当你打印时,它实际上打印了main中声明的a的垃圾值。如果您想在main中使用A中的a,则在包含main的源文件中使用cout<<A::ausing namespace A;

"翻译单元"是指编译器一次处理的代码块的技术术语。通常这是一个.cpp源文件和它包含的所有头文件。

在实践中,这通常意味着翻译单元被编译成一个目标文件。这个目标文件不是完整的程序;它必须与其他目标文件"链接"才能生成最终的程序。"链接"过程就是简单地将在一个翻译单元中定义并在一个或多个其他翻译单元中使用的各种功能进行匹配。

例如,您的翻译单元调用printf,但是printf的定义(机器代码)实际上在另一个翻译单元中。所以链接器必须知道1)printf的实际定义在哪里,2)它在代码中的调用位置,这样它就可以将1)的地址插入到2)中。

printf是具有外部链接的事物的一个例子;它可以链接到其翻译单元外部的事物。另一方面,具有内部链接的内容只能在其翻译单元内链接。因此,在您的示例中,main可以访问在名称空间级别声明为staticA::a,但是在该翻译单元之外定义的函数无法看到A::a。这是因为编译器从object文件的链接表中省略了对A::a的引用。

最后,在你的例子中发生的是,main看到的a是它在自己内部声明的,它是未初始化的。这就是为什么它打印了一个垃圾值。如果您将main更改为:

int main()
{
    printf("%dn", A::a);
}

它将打印5

它所表示的实体可以被同一翻译单元中其他作用域的名称引用。

为了使这一点有意义,你必须理解实体和名称之间的区别。

在main函数中,您创建了一个新实体,并将其命名为a。该名称不是指名称空间a中称为a的同一实体,它是一个不同的实体,不仅因为它具有不同的链接,还因为它位于不同的名称空间。

局部变量默认没有链接,因此它们总是指定一个新的实体。例如

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.
}

在这种情况下,您有两个实体,都命名为a,但它们引用不同的实体,因为它们在不同的作用域中具有不同的链接。

标准所指的情况是这样的:

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.
}

现在您只有一个实体,但是在两个不同的作用域中仍然有两个名称。这两个名字指的是同一个实体。

这是一个非常棘手的问题。因为f()内部的声明有extern,所以您说您希望f的a引用在其他地方定义的实体。然而,由于a在全局作用域中已经声明为static,这使得a具有内部链接而不是外部链接。

请注意,对于具有内部链接的同一实体使用两个名称并没有太大的实际价值,因为您总是可以使用第一个名称来代替。