6

显然,

由于涉及 C 史前史的原因,可以在同一范围内声明具有相同名称的结构和非结构。-(Bjarne Stroustrup - C++ 编程语言。第 4 版

例如:

struct Ambig {};

// the struct must be referred to with the prefix struct
void Ambig(struct Ambig* buf) {}

我只是好奇最初的原因是什么?如果不理解,这似乎是一个糟糕的语言设计示例,会导致歧义并且令人困惑。

4

4 回答 4

6

正如您在 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,后跟符号)中,在查找中忽略非类型名称。unionenum

于 2013-08-15T09:12:56.120 回答
3

我只是好奇最初的原因是什么?如果不理解,这似乎是一个糟糕的语言设计示例,会导致歧义并且令人困惑。

在 C 中,它是名称空间的第一个实现。标识符存在于不同的命名空间中,如果它们在不同的命名空间中声明,它们可以具有相同的名称。结构标记和普通标识符的命名空间并不是 C 中仅有的两个命名空间。C 中有四个命名空间:

(C99,6.2.3 标识符 p1 的名称空间)“因此,各种类别的标识符有单独的名称空间,如下所示:

— 标签名称(通过标签声明和使用的语法消除歧义);

— 结构体、联合体和枚举的标签(通过以下 any24 消除歧义)关键字 struct、union 或 enum);

——结构或工会的成员;每个结构或联合对其成员都有一个单独的名称空间(通过用于通过 . 或 -> 运算符访问成员的表达式的类型来消除歧义);

— 所有其他标识符,称为普通标识符(在普通声明符中声明或作为枚举常量声明)。”

于 2013-08-15T09:11:45.627 回答
3

像这样的原因与从 C 继承的 C++ 有关。它没有“添加”到 C++,它存在是因为它在 C 中以这种方式工作。

在 C 中,您必须使用struct Xand union Y(C 中没有class关键字),或者使用typedef struct X A;然后使用名称A而不是strcut X(其中 X 和 A 可以是相同的名称)。

在 C++ 中,只要名称是唯一的,编译器就会理解它X指的是struct X. 您不必在名称前键入或struct,也不必使用来创建新的独立名称。unionclasstypedef

由于 C++ 旨在允许(尽可能)使用 C 语法,因此struct X在引用结构时仍然允许编写。这允许使用在其他方面不明确的名称。

除非历史设计决策要求,否则强烈建议不要使用这种“可能性”,因为它只会带来更多的混乱......

于 2013-08-15T09:09:33.740 回答
1

在结构之前添加struct是完全合法的 C。因此一些 C 代码也适用于 C++。
你期待什么?C++是基于C的。

在 c++ 中,我们避免struct在每个结构之前使用。我从未在生产代码中真正看到过它。

关于歧义,我认为没有人知道他们为什么允许这样做。但我相信这是因为添加struct. 你基本上告诉编译器这不是一个函数,因此它possible meaning被消除了。

于 2013-08-15T08:49:21.653 回答