外部块作用域变量的链接,C

ign*_*tec 5 c extern linkage

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?
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用不同的编译器对其进行测试,但似乎链接主题不是非常团结的主题。

das*_*ght 4

C 对所有全局变量使用平面名称空间。与 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
}
Run Code Online (Sandbox Code Playgroud)

这个例子打印

42 52
123.250000 321
Run Code Online (Sandbox Code Playgroud)

当您跨多个翻译单元更改类型时,C++ 将在链接时捕获它,而 C 将正常链接,但会产生未定义的行为。

  • @igntec根据上面引用的标准部分,它是`static int b`,而不是`int b = 321`,因为标准说“如果先前的声明指定内部或外部链接”。`static int b` 指定内部链接,而 `int b = 321` 没有链接。 (2认同)