显然,
由于涉及 C 史前史的原因,可以在同一范围内声明具有相同名称的结构和非结构。-(Bjarne Stroustrup - C++ 编程语言。第 4 版)
例如:
struct Ambig {};
// the struct must be referred to with the prefix struct
void Ambig(struct Ambig* buf) {}
我只是好奇最初的原因是什么?如果不理解,这似乎是一个糟糕的语言设计示例,会导致歧义并且令人困惑。
显然,
由于涉及 C 史前史的原因,可以在同一范围内声明具有相同名称的结构和非结构。-(Bjarne Stroustrup - C++ 编程语言。第 4 版)
例如:
struct Ambig {};
// the struct must be referred to with the prefix struct
void Ambig(struct Ambig* buf) {}
我只是好奇最初的原因是什么?如果不理解,这似乎是一个糟糕的语言设计示例,会导致歧义并且令人困惑。
正如您在 Stroustrup 的引述中所述,原因是历史性的。在 C 中,您必须始终在结构名称前加上struct
; 结构的名称(如联合或枚举的名称)称为标记,与其他符号位于完全不同的名称空间中。所以像:
struct stat
{
// ...
};
int stat( char const* filename, struct stat* buf );
是完全合法的。(实际上,以上是 Posix 的一部分)。
在 C++ 中,类的名称(用class
,struct
或
声明union
)或枚举与其他所有名称都位于相同的命名空间中,并且与 C 不同,您可以编写如下内容:
struct MyClass {};
MyClass variableName;
这将是不合法的 C。在 C 中,第二行必须是:
struct MyClass variableName;
问题是 C++ 需要能够使用 C 中定义的接口(如上面的 Posix 接口)。所以 C++ 定义了一些特殊的规则来允许它:你可以给一个变量或一个函数和一个类类型同名。当您这样做时,变量或函数名称具有优先权,并隐藏类名称,除非在“详细类型说明符”(即class
,,
或struct
,后跟符号)中,在查找中忽略非类型名称。union
enum
我只是好奇最初的原因是什么?如果不理解,这似乎是一个糟糕的语言设计示例,会导致歧义并且令人困惑。
在 C 中,它是名称空间的第一个实现。标识符存在于不同的命名空间中,如果它们在不同的命名空间中声明,它们可以具有相同的名称。结构标记和普通标识符的命名空间并不是 C 中仅有的两个命名空间。C 中有四个命名空间:
(C99,6.2.3 标识符 p1 的名称空间)“因此,各种类别的标识符有单独的名称空间,如下所示:
— 标签名称(通过标签声明和使用的语法消除歧义);
— 结构体、联合体和枚举的标签(通过以下 any24 消除歧义)关键字 struct、union 或 enum);
——结构或工会的成员;每个结构或联合对其成员都有一个单独的名称空间(通过用于通过 . 或 -> 运算符访问成员的表达式的类型来消除歧义);
— 所有其他标识符,称为普通标识符(在普通声明符中声明或作为枚举常量声明)。”
像这样的原因与从 C 继承的 C++ 有关。它没有“添加”到 C++,它存在是因为它在 C 中以这种方式工作。
在 C 中,您必须使用struct X
and union Y
(C 中没有class
关键字),或者使用typedef struct X A;
然后使用名称A
而不是strcut X
(其中 X 和 A 可以是相同的名称)。
在 C++ 中,只要名称是唯一的,编译器就会理解它X
指的是struct X
. 您不必在名称前键入或struct
,也不必使用来创建新的独立名称。union
class
typedef
由于 C++ 旨在允许(尽可能)使用 C 语法,因此struct X
在引用结构时仍然允许编写。这允许使用在其他方面不明确的名称。
除非历史设计决策要求,否则强烈建议不要使用这种“可能性”,因为它只会带来更多的混乱......
在结构之前添加struct
是完全合法的 C。因此一些 C 代码也适用于 C++。
你期待什么?C++是基于C的。
在 c++ 中,我们避免struct
在每个结构之前使用。我从未在生产代码中真正看到过它。
关于歧义,我认为没有人知道他们为什么允许这样做。但我相信这是因为添加struct
. 你基本上告诉编译器这不是一个函数,因此它possible meaning
被消除了。