因此,我对代码进行了一些更改之后得到了以下警告:
warning: declaration of 'struct Thing' will not be visible
outside of this function
This excellent answer已解决问题。
然后我变得有些困惑。事实证明,以下是我的程序在出现错误之前:
struct OtherThing {
struct Thing* t; // <-- struct Thing declared here
};
void func(struct Thing* t);
int main(void) {
return 0;
}
这是发出警告的程序:
struct OtherThing {
int t; // <-- struct Thing no-longer declared here
};
void func(struct Thing* t);
int main(void) {
return 0;
}
如果我正确理解这一点-如链接的答案中所述,在函数签名内声明的struct
声明与普通变量具有相同的作用域规则。
但是-在不同的struct
定义中声明的struct
声明在'}'结尾之后继续吗?>
我的理解正确吗?如果是这样的话–并非相同的作用域规则适用于struct
声明和普通变量(与链接的答案相反)。这种设计背后的逻辑是什么?
答案 0 :(得分:1)
如果范围是不同的结构定义,结构声明是否在声明的范围之后?
这个问题有一个错误的前提。结构定义不是范围,因此结构声明的范围不能是封闭的结构声明。范围必须是文件范围,函数原型范围或块范围。
结构声明不构成范围-绑定结构声明的花括号不是与范围相关联的块。因此,结构声明内部的结构声明与未封闭的结构声明的行为类似-为该结构声明的标签在封闭的结构外部可见。
考虑一下:
struct Outer
{
struct Inner *Member;
};
这将外部和内部声明为结构标签。两者的作用域相同(起点略有不同;每个作用域的范围均从其名称出现的地方开始)。如果这些出现在任何功能之外,则它们具有文件作用域。如果它们出现在 block 中(使用{
…}
的 compound语句),则它们具有块作用域。如果它们出现在函数的参数声明中,则它们具有函数参数范围(但这通常对结构没有用)。请注意,复合语句是{
和}
中的语句列表。结构声明中使用的花括号不构成复合语句。
人们可能会觉得范围仅限于结构声明,因为结构成员名称(如Member
在结构外部无法使用)。但这是出于不同的原因:结构成员名称位于单独的名称空间中。每个结构都有其自己的名称空间,其成员名称位于其名称空间中。相比之下,所有结构/联合/枚举标签只有一个名称空间(所有普通标识符只有一个名称空间,所有goto
标签只有一个名称空间)。
此设计背后的逻辑是什么?
最初在C语言中,成员名称没有其自己的名称空间-您不能在不同结构中具有相同的成员名称,至少从结构开始处不能具有不同的偏移量。为每个结构提供自己的名称空间是一项宝贵的改进,因为不同结构的声明不会交互,并且程序员不必担心它们包含的标头声明了哪些成员名。而且此更改并没有在语法上更改语言:成员名称始终在结构的上下文中使用,因此,始终很清楚成员名称所属的结构,并且旧代码继续适用于此更改。
关联结构标签(或类似地,类型定义)将需要对语言进行更改。您将需要一种方法来指定标签所引用的结构。 C ++使用其::
语法来做到这一点。我不能说是否对C考虑过此类更改的历史,但我们至少可以看到,这将带来一定的成本,并且很可能破坏了现有代码-引用另一个结构内部声明的结构标签的任何代码都将具有必须进行更改以包括其所指结构的新规范。