以下代码正在成功编译,即使struct中的char * name声明没有分号。
#include<stdio.h>
typedef struct map
{
int id;
char *name
}map;
int main()
{
return 0;
}
答案 0 :(得分:2)
自C2011起的struct
和union
声明的语法:
struct-or-union-specifier:
struct-or-union identifieropt { struct-declaration-list }
struct-or-union identifier
struct-or-union:
struct
union
struct-declaration-list:
struct-declaration
struct-declaration-list struct-declaration
struct-declaration:
specifier-qualifier-list struct-declarator-listopt ;
static_assert-declaration
specifier-qualifier-list:
type-specifier specifier-qualifier-listopt
type-qualifier specifier-qualifier-listopt
struct-declarator-list:
struct-declarator
struct-declarator-list , struct-declarator
struct-declarator:
declarator
declaratoropt : constant-expression
static_assert-declaration:
_Static_assert ( constant-expression , string-literal ) ;
C 2011 Online Draft,6.7.2.1
非常明确 - struct-declaration-list
中的每个声明都必须以;
终止 - 在此之前不允许删除分号关闭}
。除非你以某种方式压制它,否则gcc 应在这里发出诊断信息。 “
修改强>
Myst在这里提出了一个有效点 - gcc发出警告,但不会停止翻译并仍然生成可执行文件(除非我指定-Werror
或类似的东西)。但是,为什么它与6.7.2.1/8无关。原因是这个特定的语法错误相对容易恢复 - 缺少所需的分号,但由于下一个标记是}
或struct
定义的结束union
,编译器可以安全地假设它被视为有效的成员声明并继续前进。 gcc发出警告(因为诊断必须在语法违规时发出),但此时没有理由停止翻译。
Myst引用的段落与
等情况有关struct foo;
struct bar {
struct foo blah;
};
当我们尝试声明struct foo
成员时,blah
类型尚未完成;编译器不知道要为它预留多少空间。在我们看到其定义的结束struct foo
之前,}
将无法完成,因此在此之前我们无法创建struct foo
的实例。
为了扩展我在评论中提出的观点,C标准没有区分“警告”和“错误” - 它只要求发布某种诊断 语法错误或约束违规:
5.1.1.3诊断
1符合要求的实施应至少产生一条诊断信息(在 如果是预处理翻译单元或翻译单元,则是实现定义的方式 包含违反任何语法规则或约束的行为,即使行为也是明确的 指定为未定义或实现定义。诊断消息不一定是 在其他情况下产生。 9) 9)意图是实现应该识别每个的性质,并在可能的情况下进行本地化 违反。当然,只要a,实现就可以自由地产生任意数量的诊断 有效的程序仍然正确翻译。它也可能成功翻译无效程序。
个别编译器可以决定特定诊断是否被视为“警告”或“错误”,并且他们可以决定是否停止对特定错误的转换。与上面的段落一样,允许编译器翻译无效程序。
答案 1 :(得分:-1)
我怀疑这个问题可能与C11标准有关(我没有更旧的版本,但它可能是相同的),它指定了(6.7.2.1第8段):
struct-or-union-specifier中struct-declaration-list的存在在转换单元中声明了一个新类型。 struct-declaration-list是结构或联合成员的一系列声明。如果struct-declaration-list不包含任何命名成员(直接或通过匿名结构或匿名联合),则行为未定义。 类型不完整,直到终止列表的
}
之后,之后完成。
这意味着正在执行两项操作:
终止列表(struct-declaration-list)。
完成类型(结构或联合)。
我认为这可能(错误地)被构造为意味着}
可以通过作为终止结构声明节点的分号闭包来终止struct-declaration-list。
否则,有人可能会争辩说,应该有一个动作(类型的完成)而不是两个(结束声明列表的结束+类型的完成)。
这种宽松的解释(可能不反映作者的意图,恕我直言)使这成为一个可疑的宽松语言解释特征而不是问题。
无论哪种方式,如果缺少分号,则clang
和gcc
的当前版本报告警告(使用c11标志时) )。这表明行为的一致性,这表明这是对标准的解释而不是错误。
考虑到这种可能的歧义以及声明后}
不会对代码含义产生任何疑问这一事实,我认为编译器开发人员倾向于提出警告而不是错误,这肯定是合法的,没有错误报告是必需的。
修改强>
我阅读了John Bode的回答和Olaf的评论并相应地编辑了我的答案,以使我的观点更加清晰。
虽然约翰和奥拉夫都比我自己聪明,虽然我看到了他们观点的优点,但我认为标准在这一点上并不够明确。
John的答案中的详细引用确实将每个struct-declaration
定义为以分号(;
)结尾,这意味着列表应以分号结尾。
然而,同一部分的文字解释似乎表明}
可能具有双重功能。
这个建议的解释空间可能过于宽松,但是在编译代码(恕我直言)时提出警告而不是错误是一个足够好的理由 - 特别是代码本身可以'被误解了。