外部块范围变量C的链接

外部块范围变量C的链接,c,extern,linkage,C,Extern,Linkage,C标准规定: 对于在中使用存储类说明符extern声明的标识符 该标识符的先前声明可见的范围,31) 如果先前的声明指定了内部或外部链接,则 后面声明中标识符的链接与 先前声明中指定的链接。如果没有事先声明 可见,或者如果先前的声明未指定任何链接,则 标识符具有外部链接 不清楚的是,前面的标识符是否必须具有相同的类型(注意:C++标准明确地表示“同名的实体和类型”)。例如: static int a; // internal linkage void f() { float a;

C标准规定:

对于在中使用存储类说明符extern声明的标识符 该标识符的先前声明可见的范围,31) 如果先前的声明指定了内部或外部链接,则 后面声明中标识符的链接与 先前声明中指定的链接。如果没有事先声明 可见,或者如果先前的声明未指定任何链接,则 标识符具有外部链接

不清楚的是,前面的标识符是否必须具有相同的类型(注意:C++标准明确地表示“同名的实体和类型”)。例如:

static int a;   // internal linkage

void f()
{
    float a;      // no linkage, instead of 'int a' we have 'float a'

    {
        extern int a;     // still external linkage? or internal in this case?
        a = 0;            // still unresolved external?
    }
}
file-one.cpp:

int a;                // C decorated name: _a
                      // C++ decorated name (VC++): ?a@@3HA

//------------------------------------------------

file-two.cpp:

float a;              // C decorated name: _a
                      // C++ decorated name (VC++): ?a@@3MA

我试着用不同的编译器来测试它,但似乎linkage subject并不是一个非常团结的编译器。

C对所有全局变量都使用平面名称空间。与C++不同,它要求链接器注意全局变量的类型(查找名称以获取更多信息),C将此要求提交给程序员。 在同一转换单元内更改链接时,重新声明不同类型的变量是错误的

我将使用您的示例进行一个小的添加

static int a;   // internal linkage
static int b;   // internal linkage

void f()
{
    float a = 123.25; // this variable shadows static int a
    int b = 321;      // this variable shadows static int b

    { // Open a new scope, so the line below is not an illegal re-declaration
        // The declarations below "un-shadow" static a and b
        extern int a; // redeclares "a" from the top, "a" remains internal
        extern int b; // redeclares "b" from the top, "b" remains internal
        a = 42;       // not an unresolved external, it's the top "a"
        b = 52;       // not an unresolved external, it's the top "b"
        printf("%d %d\n", a, b); // static int a, static int b
    }
    printf("%f %d\n", a, b);     // local float a, int b
}
此示例打印

42 52
123.250000 321

当你在多个翻译单元之间更改类型时,C++会在链接时捕获它,而C将链接精细,但会产生未定义的行为。

< P>我想我有答案。我将大体上写下这个主题

C标准规定:

在翻译单元集合中,每个特定 具有外部链接的标识符表示相同的实体(对象或函数)。 在一个翻译单元内,标识符的每个声明 内部链接表示同一实体

C++标准说:

当名称具有外部链接时,它所表示的实体可以是 从其他翻译单位的范围或从 同一翻译单位的其他范围。当名称具有内部 链接,它所表示的实体可以通过其他链接的名称来引用 同一翻译单元中的作用域

这有两个含义:

  • 在翻译单元集中,我们不能有多个具有相同名称的不同外部实体(C++中重载函数除外),因此表示单个外部实体的每个声明的类型应该一致。我们可以在一个翻译单元内检查类型是否一致,这是在编译时完成的。无论是在编译时还是在链接时,我们都无法检查不同翻译单元之间的类型是否一致
在C++中,我们可以在翻译单位集合中违反<代码>,我们不能有多个不同的外部实体,它们具有相同的名称< /Cord>规则,没有函数重载。因为C++具有名称类型,它编码类型信息,所以可以有多个具有相同名称和不同类型的外部实体。例如:

static int a;   // internal linkage

void f()
{
    float a;      // no linkage, instead of 'int a' we have 'float a'

    {
        extern int a;     // still external linkage? or internal in this case?
        a = 0;            // still unresolved external?
    }
}
file-one.cpp:

int a;                // C decorated name: _a
                      // C++ decorated name (VC++): ?a@@3HA

//------------------------------------------------

file-two.cpp:

float a;              // C decorated name: _a
                      // C++ decorated name (VC++): ?a@@3MA
而在C中,这实际上是一个外部实体,第一个单元中的代码将它视为
int
,第二个单元中的代码将它视为
float

  • 在一个翻译单元中,我们不能有多个具有相同名称的不同内部实体(C++中重载函数除外),因此表示单个内部实体的每个声明的类型应该一致。我们检查翻译单元中的类型是否一致,这是在编译时完成的
现在我们将更接近这个问题

C++标准说:

在块作用域中声明的函数名和 由块作用域外部声明声明的变量具有链接。如果 存在一个实体的可见声明,该实体的链接具有 相同的名称和类型,忽略在最内层外部声明的实体 块范围声明包含名称空间范围,声明 同一实体并接收上一个声明的链接。如果 有不止一个这样的匹配实体,程序是 格式不正确。否则,如果未找到匹配的实体,则块范围 实体接收外部链接

在这里,我们没有以前使用相同名称(
a
)和类型(
float
)的实体声明,因此
extern float a
的链接是外部的。因为我们已经在这个翻译单元中有了带有外部链接的
inta
,并且名称相同,所以类型应该一致。在这种情况下,它们没有,因此我们有编译时错误

// C++

static int a;             // internal linkage

void f()
{
    extern float a;       // external linkage
}
// C

static int a;             // internal linkage

void f()
{
    extern float a;       // internal linkage
}
在这里,我们没有以前使用相同名称(
a
)和类型(
float
)的实体声明,因此
extern float a
的链接是外部的。这意味着我们必须在另一个翻译单元中定义
浮动a
。请注意,我们在一个翻译单元中有相同的标识符,具有外部和内部链接(我不知道为什么C会考虑这种未定义的行为,因为我们可以在不同的翻译单元中有相同名称的内部和外部实体)

这里前面的声明
inta
没有链接,因此
extern inta
有外部链接。这意味着我们必须在另一个翻译单元中定义
inta

C标准规定:

对于在中使用存储类说明符extern声明的标识符 该标识符的先前声明可见的范围,31) 如果先前的声明指定了内部或外部链接,则 后面声明中标识符的链接与 先前声明中指定的链接。如果没有事先声明 可见,或者如果先前的声明未指定任何链接,则 标识符具有外部链接

所以我们可以看到,在C中只考虑名称(不考虑类型)

在此,标识符
a
的先前声明具有外部链接,因此
extern float a
的链接相同(外部)。自从
// C

static int a;             // internal linkage

void f()
{
    extern float a;       // internal linkage
}
// C

static int a;        // internal linkage

void f()
{
    int a;            // no linkage

    {
        extern int a;    // external linkage
    }
}