外部块范围变量C的链接
C标准规定: 对于在中使用存储类说明符extern声明的标识符 该标识符的先前声明可见的范围,31) 如果先前的声明指定了内部或外部链接,则 后面声明中标识符的链接与 先前声明中指定的链接。如果没有事先声明 可见,或者如果先前的声明未指定任何链接,则 标识符具有外部链接外部块范围变量C的链接,c,extern,linkage,C,Extern,Linkage,C标准规定: 对于在中使用存储类说明符extern声明的标识符 该标识符的先前声明可见的范围,31) 如果先前的声明指定了内部或外部链接,则 后面声明中标识符的链接与 先前声明中指定的链接。如果没有事先声明 可见,或者如果先前的声明未指定任何链接,则 标识符具有外部链接 不清楚的是,前面的标识符是否必须具有相同的类型(注意:C++标准明确地表示“同名的实体和类型”)。例如: static int a; // internal linkage void f() { float a;
不清楚的是,前面的标识符是否必须具有相同的类型(注意: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++中重载函数除外),因此表示单个外部实体的每个声明的类型应该一致。我们可以在一个翻译单元内检查类型是否一致,这是在编译时完成的。无论是在编译时还是在链接时,我们都无法检查不同翻译单元之间的类型是否一致
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++中重载函数除外),因此表示单个内部实体的每个声明的类型应该一致。我们检查翻译单元中的类型是否一致,这是在编译时完成的
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
}
}