【发布时间】:2016-07-14 07:45:54
【问题描述】:
想象一下我们有这个:
void f(struct s *);
通过阅读标准(6.2.1 美元),我对标签的范围有点困惑。首先是这个:
标签名称是唯一一种具有函数作用域的标识符。它可以使用(在一个 goto 语句)出现在函数中的任何位置,并且被隐式声明 通过它的句法外观(后跟一个 : 和一个语句)。
每个其他标识符的范围由其声明的位置决定(在声明符或类型说明符中)。如果声明者或 声明标识符的类型说明符出现在任何 块或参数列表,标识符具有文件范围,其中 在翻译单元的末尾终止。如果声明者或 声明标识符的类型说明符出现在块内或 在函数定义的参数声明列表中, 标识符具有块作用域,它在 关联块。 如果声明符或类型说明符声明 标识符出现在参数声明列表中 函数原型(不是函数定义的一部分),标识符 具有函数原型范围,它在 function declarator. 如果一个标识符指定了两个不同的 相同名称空间中的实体,范围可能重叠。如果是这样,则 一个实体的范围(内部范围)将严格在 另一个实体的范围(外部范围)。在内部范围内, 标识符指定在内部范围内声明的实体;这 在外部范围内声明的实体在内部隐藏(不可见) 内部范围。
由于标识符属性被早期定义为:
- 标识符可以表示一个对象;一个函数; 结构的标签或成员、联合或枚举;类型定义名称;标签名称;一种 宏名;或宏参数。相同的标识符可以表示 程序中不同点的不同实体。一个成员 枚举称为枚举常数。宏名称和宏 这里不考虑参数,因为在 程序翻译的语义阶段 任何出现的宏名称 在源文件中被预处理标记序列替换 构成它们的宏定义。
这让我得出这个结论:
由于类型说明符struct s 在“函数原型中的参数声明列表”中声明标识符s,因此它具有(标识符s)函数原型范围。意思是这样的:
void f2()
{ //inside **some** function block after the above declaration
struct s { int a; } v; //new s identifier being declared
f(&v); //not compatible types
}
但是在这之后我们有:
- 结构、联合和枚举标记的范围紧随标记出现在类型说明符中之后开始,该类型说明符声明 每个枚举常量的作用域都紧随其后 其定义枚举数在枚举数列表中的出现。任何其他 标识符的范围在其完成后开始 声明者。
这意味着完全不同的东西:
void f3()
{ //inside **some** function block after the above declaration
struct s { int a; } v; //completing incomplete type
f(&v); //ok
}
似乎 gcc 和 clang 遵循 p4(总结为编译f 声明的警告):
warning: ‘struct s’ declared inside parameter list will not be visible outside of this definition or declaration
void f(struct s *);
使用clang的情况类似:
warning: declaration of 'struct s' will not be visible outside of this function [-Wvisibility]
void f(struct s *);
有谁愿意解释在函数原型f 中确定s 标识符范围的正确方法是什么?
我指的是 INCITS/ISO/IEC 9899-2011[2012] 标准文件;使用带有以下标志的 gcc 编译器(和 clang)进行编译:
-std=c11 -pedantic
请求完整的代码:
目前(通过使用 GCC 和 clang 编译):
void f(struct s {int _;});
struct s g;
会给出以下错误(通过clang):
prog.c:1:15: warning: declaration of 'struct s' will not be visible outside of this function [-Wvisibility]
void f(struct s {int _;});
^
prog.c:3:10: error: tentative definition has type 'struct s' that is never completed
struct s g;
^
prog.c:3:8: note: forward declaration of 'struct s'
struct s g;
在这种情况下,引用标准可能是正确的行为,也可能不是正确的行为(p4 和 p7 冲突 - 或者是吗? - 我不知道)。
g 的声明中的 p7 struct s 应该引用 f 的函数原型中声明的相同标识符。因此,定义类型不完整的变量应该不会导致任何编译器错误。
但是在f的函数原型中声明的p4 struct s必须具有在函数声明符末尾终止的范围。所以struct s 的声明在g 的声明中应该创建另一个标识符s(作为不完整结构的标记,因此错误消息)。
【问题讨论】:
-
请向我们提供一段完整的代码,显示预期和意外的行为以及错误/警告在哪一行。
-
@MohitJain 不完全是。
-
@FISOCPP 我说的是相关而不是重复。
标签: c scope language-lawyer c11