据我所知,这在C语言中是合法的:
foo.c
struct foo {
int a;
};
bar.c
struct foo {
char a;
};
但是对于函数来说,这样做是不合法的:
foo.c
int foo() {
return 1;
}
bar.c
int foo() {
return 0;
}
这会导致链接错误(函数foo
的多重定义)。
为什么会这样?C语言无法处理结构体名称和函数名称之间的差异。是否扩展到C ++?
为什么会这样呢?
struct foo {
int a;
};
定义了一个创建对象的模板,不会创建任何对象或函数。除非struct foo
在你的代码中使用过,否则对于编译器/链接器而言,这些代码行就好像不存在一样。
请注意,C和C++在处理不兼容的struct
定义方面有所区别。
在C程序中,你发布的代码中struct foo
的不同定义是可以的,只要不混合它们的使用即可。
但是,在C++中是不合法的。在C++中,它们具有外部链接并且必须被相同地定义。有关详细信息,请参见3.2 One definition rule/5。
struct foo
,它将使用该定义,如果我在bar.c中使用它,它将使用来自bar的定义,不是吗? - V0ldekfoo
传递给期望来自bar.c的foo
的函数,那么你应该没问题。 - R Sahustruct foo
,肯定会出错。 - V0ldekstruct
没有外部定义这种东西。它只是编译 .c
文件时编译器所看到的内容。 - R Sahusizeof
或 _Alignof
运算符的操作数之一且其结果是整数常量),那么整个程序中必须有一个标识符的外部定义;否则,不应有超过一个。
C ++中扩展了链接的概念:它将特定的链接分配给更广泛的实体,包括类型。在C ++中,类类型具有链接性。在命名空间范围内声明的类具有外部链接。C++的"一个定义规则"明确规定,如果具有外部链接的类在多个翻译单元中有几个定义,则应在所有这些翻译单元中等效地定义它们( http://eel.is/c++draft/basic.def.odr#12 )。因此,在C ++中,您的struct
定义将是非法的。
由于C++ ODR规则(但本质上与C中相同的原因),您的函数定义在C++中仍然是非法的。
sizeof
和_Alignof
运算符的操作数可以是具有超过一个定义的外部链接标识符?还是它暗示这些运算符的操作数不需要是明确定义的标识符?也就是说,已声明但未定义的标识符可以传递给这些运算符。 - Nicholas Cousar你的函数定义都声明了一个名为foo
的具有外部链接性质的实体,C标准规定,具有外部链接性质的实体不得有超过一个的定义。你定义的结构体类型不是具有外部链接性质的实体,因此可以有多个struct foo
的定义。
如果你使用相同的名称声明具有外部链接性质的对象,那么将会出现错误:
foo.c
struct foo {
int a;
};
struct foo obj;
bar.c
struct foo {
char a;
};
struct foo obj;
现在你有两个名为obj
的对象,它们都具有外部链接,这是不允许的。
即使其中一个对象仅被声明而不被定义,这仍然是错误的:
foo.c
struct foo {
int a;
};
struct foo obj;
bar.c
struct foo {
char a;
};
extern struct foo obj;
由于obj
的两个声明引用同一对象,但它们的类型不兼容(因为struct foo
在每个文件中的定义不同),所以这是未定义的。
C++有类似的规则,但更加复杂,以考虑inline
函数和inline
变量、模板和其他C++特性。在C++中,相关要求被称为单一定义规则(ODR)。一个值得注意的区别是,即使两个不同的struct
定义从未用于声明具有外部链接或在翻译单元之间“共享”的对象,C++也不允许这样做。
struct foo
的两个声明在类型不同的成员之间不兼容。只要你不做任何事情来混淆它们,在每个翻译单元中都可以同时使用它们。
例如,如果你这样做:
foo.c:
struct foo {
char a;
};
void bar_func(struct foo *f);
void foo_func()
{
struct foo f;
bar_func(&f);
}
bar.c:
struct foo {
int a;
};
void bar_func(struct foo *f)
{
f.a = 1000;
}
bar_func
期望的结构体 struct foo
,但是 foo_func
提供的 struct foo
不兼容,这将导致 未定义行为。总而言之,两个1 如果两个类型的类型相同,则它们具有兼容的类型。判断两个类型是否兼容的其他规则在类型说明符的 6.7.2 节,类型修饰符的 6.7.3 节和声明符的 6.7.6 节中描述。此外,如果在不同的翻译单元中声明了两个结构体、联合体或枚举类型,则它们的标记和成员满足以下要求时它们是兼容的:如果其中一个带标记,则另一个也必须带有相同的标记。如果两个都在其各自的翻译单位内任何地方完成,则适用以下附加要求:应当存在一对一的对应关系,使得每一对相应的成员都用兼容类型声明;如果一对成员中的一个带有对齐说明符,则另一个带有等效的对齐说明符;如果一对成员中的一个带有名称,则另一个使用相同的名称声明。对于两个结构体,相应成员应在相同的顺序中声明。对于两个结构体或联合体,相应的位域应具有相同的宽度。对于两个枚举类型,相应的成员应具有相同的值。
2 所有引用同一对象或函数的声明必须具有兼容类型;否则,行为未定义。
struct foo
实例的成员必须相同且按相同顺序,才能互相兼容。 static int foo() {
return 1;
}
bar.c
static int foo() {
return 0;
}
struct
是一个声明,它声明了一个新的数据类型,但并不创建任何新的对象。相反,函数是被定义的(您创建了一个新的函数实体)。 - DYZstruct foo
但没有定义它吗? - curiousguy