为什么non-extern可以在C / C ++中的.h文件中?

时间:2011-03-23 11:58:05

标签: c symbols header-files

this file为例,有许多非外部结构,如:

struct list_head source_list;

当多个编译单元包含此头文件时,它如何工作?

应该有错误报告相同的符号被定义两次,对吗?

4 个答案:

答案 0 :(得分:2)

技术上应该存在,但是这种使用已经存在多年并且无法根除(已经尝试过;一些供应商经常决定使其成为错误,并在大约一百个左右的错误报告之后恢复)。小心翼翼地,.h文件应声明extern一个 .c / .cpp文件应该定义它。

简而言之,当您未指定顶级变量的链接(staticextern等)时,它会被声明为“常见”。在链接时,如果对该变量的所有引用都是相同的大小(和类型,如果可用),那么它将被分配一次,并且所有引用都指向它。如果链接器为同一个变量找到不同的大小/类型/链接,则会抛出错误。

编辑:这显然让人感到困惑。这里:

jinx:1714 Z$ cat foo.h
int foo;
extern void bar();
jinx:1715 Z$ cat foo.c
#include "foo.h"

int
main(int argc, char **argv)
{
  bar();
  return 0;
}
jinx:1716 Z$ cat bar.c
#include "foo.h"

void
bar(void)
{
  return;
}
jinx:1717 Z$ gcc -Wall foo.c bar.c -o foo
jinx:1718 Z$ ./foo
jinx:1719 Z$ _

请注意,int foo被多重定义完全没有错误。 这个就是我一直想说的。

答案 1 :(得分:1)

struct list_head source_list;字段在其他结构中声明,因此它们不是符号。

其他(顶级)结构的声明具有不同的名称,所以它也可以。

修改

请注意,此标头的所有变量都标有extern

答案 2 :(得分:1)

这个术语是“暂定”:

  

。的标识符声明   没有文件范围的对象   初始化程序,没有   存储类说明符或与   存储类说明符static,   构成一个         暂定的定义。如果翻译单元包含一个或多个   暂定的定义            标识符,并且翻译单元不包含外部   那个标识符的定义                 行为就像翻译单元包含一个   文件范围声明                  标识符,复合类型截至   翻译单元,带初始化程序                   等于0。

所以这在C中有很好的定义(但经常不赞成)。

答案 3 :(得分:0)

确实应该有extern。但是,该变量没有明确的定义,因此编译器会将其标记为extern。

如果你有

,你会收到链接器错误
struct list_head source_list = { 0 };

...因为 每个翻译单元定义一次符号(因此链接器会抱怨)。