【发布时间】:2018-12-01 05:40:53
【问题描述】:
我正在阅读 the Standard: N1570 并遇到了一些误解。我写了以下简单的例子:
test.h:
#ifndef TEST_H
#define TEST_H
extern int second;
#endif //TEST_H
test.c:
#include "test.h"
enum test_enum{
first,
second
};
但是编译失败,报错:
error: ‘second’ redeclared as different kind of symbol
second
^~~~~~
这很奇怪,因为6.4.4.3#2 部分指定:
2 声明为枚举常量的标识符具有 int 类型。
在我们的例子中,枚举常量具有文件范围,所以我希望它编译得很好。
我把上面的例子改写如下:
main.c:
extern int second;
int main(int argc, char const *argv[])
{
printf("Second: %d\n", second);
}
现在链接器抱怨:
undefined reference to `second'
为什么?它应该在test.c 中找到定义,因为Section 6.2.2#5 指定:
如果对象的标识符声明具有文件范围并且 没有存储类说明符,它的链接是外部的。
【问题讨论】:
-
您也可以参考带有C11 Standard - Draft n1570的网页,以防止每个人每次都下载整个
.pdf(两者都可以,只是一个建议) -
你包括
test.h,其中包含extern int second;当你声明一个enum时,标签(枚举成员)也是全局常量——编译器看到两个second的声明——因此是重新声明。 -
@DavidC.Rankin 问题是如果我用
int替换枚举常量的声明,它会按预期工作。 -
要么将
enum移动到标题并在 main 中包含test.h,要么将变量second重命名为test.h中的其他名称并在test.c中定义它。 -
第一个 sn-p 需要不同类型的不同名称空间的概念,因此标识符不会有歧义。 C 仅适用于结构成员。早期的 K&R 没有,非常痛苦。值得注意的是,C++ 最近用枚举类修复了这个问题。第二个 sn-p 在所有代码中都有 extern (“它存在于其他地方”),链接器正确地抱怨“在哪里?”删除 main.c 文件中的 extern 说“这里”。