GCC(C18)中外部变量警告的初始化

GCC(C18)中外部变量警告的初始化,c,gcc,C,Gcc,问题不是“为什么我不能初始化一个声明为extern的变量”,因为使用文件范围变量(而不是块范围变量)是完全可能的。问题是,在这种特殊情况下,GCC会产生一个警告(带有-Wall开关): extern int n = 10; // file scope declaration GCC收益率: test.c:5:12: warning: ‘n’ initialized and declared ‘extern’ 不过,代码工作得很好 此外,请注意,以下定义与第一个定义完全相同: int n =

问题不是“为什么我不能初始化一个声明为extern的变量”,因为使用文件范围变量(而不是块范围变量)是完全可能的。问题是,在这种特殊情况下,GCC会产生一个警告(带有
-Wall
开关):

extern int n = 10;  // file scope declaration
GCC收益率:

test.c:5:12: warning: ‘n’ initialized and declared ‘extern’
不过,代码工作得很好

此外,请注意,以下定义与第一个定义完全相同:

int n = 10;  // file scope declaration
在这两种情况下,变量具有相同的链接和存储类型。问题是,两者完全相同,第二个版本在GCC中不会产生任何警告(使用
-Wall

为什么呢

我的猜测是,您通常使用
extern
显式设置一个提醒,提醒您这是一个引用在别处定义的外部对象的声明,这样您就不应该(尽管可以)初始化变量(请记住,该标准不允许在同一链接内定义两次变量,在本例中为外部变量)

那么,这是一个正确的猜测,还是我看不到更多的猜测?

关键字extern用于声明变量,但不定义它(类似于函数声明)。通常在头文件中用于从模块导出变量。但是,最好引入一个返回其值的函数

例如:

M.h

医学博士


编译器可以对它喜欢的任何事情发出警告。如果它注意,它会对它认为“可疑”的事情发出警告

这里也是

我个人对推理的看法与你的一致:

我的猜测是,您通常使用
extern
显式设置一个提醒,提醒您这是一个引用在别处定义的外部对象的声明,因此您不应该(尽管可以)初始化变量(请记住,该标准不允许在同一链接内定义两次变量,在本例中为外部变量)

GCC发现初始化显式
extern
声明的变量是可疑的,因为通常在一个文件中定义变量,然后在另一个文件中定义变量更为常见,这可能取决于上下文,导致链接时出错,这确实可能是原因,但我们的假设值不高


实际“为什么”的问题您需要询问GCC本身的实现者。

这是GCC的一个怪癖-它不是C通常编写的方式,编译器会生成警告。在初始化变量时,最简单的方法是避免使用
extern
。对于较旧版本的C标准,您会从GCC得到警告;它与C18无关。我认为这是归结为一个“为什么?”。在什么情况下这样做是有用的?请参阅2010年的GCC Bugzilla。上面的说明是关于编码风格的,并将此模式描述为“非常单一”.一些关于
extern
的C规则是混乱的,因为随着时间的推移,该语言以不同的实践发展,导致允许某些事情,不允许其他事情,并赋予某些含义的混乱。编译器警告是这种混乱历史的结果。在非定义decl中使用
extern
是常见的做法arations和not in definitions,因此编译器警告它在定义中的使用,但C标准允许它。与此问题相关:@th33lf好吧,这个问题更多地与禁用警告相关,就像讨论中的那个,没有特定的开关。虽然您所说的是典型的用法,但是关于问题中显示的代码。这只是
extern
的一个不寻常的、不直观的用法。我对第一句话基本上有一个问题。@ThomasJager即使它是有效的,为什么要这样做?使用extern的声明应该在头文件中,变量定义应该在实现文件中。有一个建议的规则,gener总之,要在多个翻译单元中使用的名称的非定义声明应该在标题中,而定义应该在源文件中。建议使用该规则,因为标题用于使其他翻译单元知道名称(因此它们应该有声明)在其中定义对象或函数会导致多个定义。您说使用
extern
的声明应该在头文件中。为什么会有这样的规则?什么是“因为”这导致了这样一个规则,并说
extern
不应该在源文件中使用?@AugustKarlstrom我同意,这就是我在对这个问题的评论中提出的观点。然而,我觉得你的回答根本没有解决这个问题,只回答了“什么是
extern
?”。第一句话意味着,如果在另一个单元中没有为带有
extern
的变量创建存储,则该变量没有任何存储。@EricPostpischil,因为据我所知,在实现文件中没有extern的用例。如果有,请告诉我。公平地说,
extern
显然是冗余的,并且dds对语句没有任何影响。它不会造成伤害,但也可以安全地忽略。编译器还试图防止潜在的链接器错误,以防变量的实际定义出现在另一个翻译单元中。
extern int M_n;
int M_n = 10;