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)
我尝试使用不同的编译器对其进行测试,但似乎链接主题不是非常团结的主题。
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 将正常链接,但会产生未定义的行为。