C++ typedef 名称在 typedef 声明中是可选的吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6399898/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 20:03:50  来源:igfitidea点击:

Is the typedef-name optional in a typedef declaration?

c++ctypedef

提问by David Rodríguez - dribeas

I was quite surprised when I saw the following code compile without errors or warnings in g++-4.2:

当我在 g++-4.2 中看到以下代码编译时没有错误或警告时,我感到非常惊讶:

typedef enum test { one };

My assumption was that if you used the typedefkeyword it would require an extra identifier as in:

我的假设是,如果您使用typedef关键字,它将需要一个额外的标识符,如下所示:

typedef enum test { one } test;

As already mentioned, g++-4.2 accepts it without even a warning. Clang++ 3.0 warns "warning: typedef requires a name", similarly Comeau warns "warning: declaration requires a typedef name", and g++-4.6 informs: "warning: 'typedef' was ignored in this declaration".

如前所述,g++-4.2 甚至没有警告就接受了它。Clang++ 3.0 警告“警告:typedef 需要一个名称”,类似的 Comeau 警告“警告:声明需要一个 typedef 名称”,并且 g++-4.6 通知:“警告:'typedef' 在此声明中被忽略”。

I have not been able to identify where in the standard this is allowed, and I find it slightly confusing that two of the compilers warn that it is required, shouldn't it be an error if the typedef-name is requiredbut not present?

我一直没能找出其中的标准,这是允许的,我觉得稍微混淆这两个编译器警告说,这是必需的,如果typedef的名称,它不应该是一个错误要求,但不存在?

UPDATE: I have checked in C with the same compilers. Clang and comeau yield the same output, gcc gives a warning: "warning: useless storage class specifier in empty declaration", which seems even more confusing.

更新:我已经使用相同的编译器检查了 C。Clang 和 comeau 产生相同的输出,gcc 给出警告:“警告:空声明中无用的存储类说明符”,这似乎更令人困惑。

UPDATE: I have checked removing the name of the enum and the results are the same:

更新:我检查了删除枚举的名称,结果是一样的:

typedef enum { one };

Similarly with a named struct:

与命名结构类似:

typedef struct named { int x };

But not with an unnamed struct, in which case the code was rejected in g++ (4.2/4.6) with "error: missing type-name in typedef-declaration", gcc (4.2/4.6) gave a warning: "warning: unnamed struct/union that defines no instances", clang++ "warning: declaration does not declare anything", comeau "error: declaration requires a typedef name"

但不是使用未命名的结构,在这种情况下,代码在 g++ (4.2/4.6) 中被拒绝,并显示“错误:typedef-declaration 中缺少类型名称”,gcc (4.2/4.6) 给出警告:“警告:未命名的结构/union 没有定义实例“,clang++”警告:声明没有声明任何东西“,comeau”错误:声明需要一个typedef名称

回答by Jonathan Leffler

It is a degenerate syntax that is allowed but provides no benefit. Most modern compilers can be provoked into emitting a warning about it; by default, they may not. Without the typedef name, the keyword typedefis superfluous; in your example, it is completely equivalent to:

这是一种允许但没有任何好处的退化语法。大多数现代编译器都会被激起发出警告;默认情况下,他们可能不会。没有 typedef 名称,关键字typedef是多余的;在您的示例中,它完全等效于:

enum test { one };

Another place where it can occur is with a structure:

另一个可能发生的地方是一个结构:

typedef struct SomeThing { int whatever; };

This is equivalent to:

这相当于:

struct SomeThing { int whatever; };

Note that typedefis officially (or syntactically) a 'storage class specifier', like static, extern, autoand register.

请注意,typedef是官方(或语法)一个“存储类说明”,如staticexternautoregister



C Standard

C标准

In ISO/IEC 9899:1999 (that's the C standard), we find:

在 ISO/IEC 9899:1999(即 C 标准)中,我们发现:

§6.7 Declarations

Syntax

declaration:

declaration-specifiersinit-declarator-listopt;

declaration-specifiers:

storage-class-specifierdeclaration-specifiersopt

type-specifierdeclaration-specifiersopt

type-qualifierdeclaration-specifiersopt

function-specifierdeclaration-specifiersopt

init-declarator-list:

init-declarator

init-declarator-list, init-declarator

init-declarator:

declarator

declarator= initializer

§6.7 声明

句法

声明

声明说明符init-declarator-list opt;

声明说明符

存储类说明符声明说明符选择

类型说明符声明说明符选择

类型限定符声明说明符opt

函数说明符声明说明符opt

初始化声明器列表

初始化声明符

init-declarator-list, init-declarator

初始化声明符

声明者

声明符=初始值设定项

And (as requested):

和(根据要求):

§6.7.1 Storage-class specifiers

Syntax

storage-class-specifier:

typedef

extern

static

auto

register

§6.7.1 存储类说明符

句法

存储类说明符:

typedef

extern

static

auto

register

If you track through that syntax, there are a lot of degenerate possibilities, and what you showed is just one of the many.

如果您跟踪该语法,就会发现有很多退化的可能性,而您所展示的只是众多可能性之一。



C++ Standard

C++标准

It is possible that C++ has different rules.

C++ 可能有不同的规则。

In ISO/IEC 14882:1998 (the original C++ standard), we find in §7.1.1 'Storage class specifiers' that C++ does not treat typedefas a storage class; the list adds mutableand excludes typedef. So, the grammatical specification of typedefin C++ is definitely different from the C specification.

在 ISO/IEC 14882:1998(原始 C++ 标准)中,我们在第 7.1.1 节“存储类说明符”中发现 C++ 不将其typedef视为存储类;该列表添加mutable和排除typedef. 所以,typedefC++中的语法规范与C规范肯定是不同的。

§7 Declarations

§7 声明

Declarations specify how names are to be interpreted. Declarations have the form

声明指定如何解释名称。声明具有以下形式

declaration-seq:

declaration

declaration-seq declaration

declaration:

block-declaration

function-definition

template-declaration

explicit-instantiation

explicit-specialization

linkage-specification

namespace-definition

block-declaration:

simple-declaration

asm-definition

namespace-alias-definition

using-declaration

using-directive

simple-declaration:

decl-specifier-seqoptinit-declarator-listopt;

...

?5 If the decl-specifier-seq contains the typedefspecifier, the declaration is called a typedefdeclaration and the name of each init-declaratoris declared to be a typedef-name, synonymous with its associated type (7.1.3).

§7.1 Specifiers [dcl.spec]

The specifiers that can be used in a declaration are

decl-specifier:

storage-class-specifier

type-specifier

function-specifier

friend

typedef

decl-specifier-seq:

decl-specifier-seqopt

decl-specifier

§7.1.1 Storage class specifiers [dcl.stc]

storage-class-specifier:

auto

register

static

extern

mutable

§7.1.2 Function specifiers [dcl.fct.spec]

function-specifier:

inline

virtual

explicit

§7.1.3 The typedef specifier [dcl.typedef]

Declarations containing the decl-specifier typedefdeclare identifiers that can be used later for naming fundamental (3.9.1) or compound (3.9.2) types. The typedefspecifier shall not be used in a function-definition (8.4), and it shall not be combined in a decl-specifier-seq with any other kind of specifier except a type-specifier.

typedef-name:

identifier

...

In a given scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers. [Example:

typedef struct s { /* ... */ } s;
typedef int I;
typedef int I;
typedef I I;

—end example]

§7.1.4 The friend specifier [dcl.friend]

The friend specifier is used to specify access to class members; see 11.4.

§7.1.5 Type specifiers [dcl.type]

type-specifier:

simple-type-specifier

class-specifier

enum-specifier

elaborated-type-specifier

cv-qualifier

声明序列:

宣言

声明序列声明

宣言:

块声明

功能定义

模板声明

显式实例化

显式专业化

链接规范

命名空间定义

块声明:

简单声明

asm-定义

命名空间别名定义

使用声明

使用指令

简单声明:

decl-specifier-seq optinit-declarator-list opt;

...

?5 如果 decl-specifier-seq 包含说明typedef符,则该声明称为typedef声明,并且每个的名称都init-declarator被声明为 typedef-name,与其关联的类型同义 (7.1.3)。

§7.1 说明符 [dcl.spec]

可以在声明中使用的说明符是

声明说明符:

存储类说明符

类型说明符

功能说明符

friend

typedef

声明说明符序列:

声明说明符序列选择

声明说明符

§7.1.1 存储类说明符 [dcl.stc]

存储类说明符:

auto

register

static

extern

mutable

§7.1.2 函数说明符 [dcl.fct.spec]

功能说明符:

inline

virtual

explicit

§7.1.3 typedef 说明符 [dcl.typedef]

包含 decl-specifier 的 typedef声明声明标识符,稍后可用于命名基本 (3.9.1) 或复合 (3.9.2) 类型。的typedef说明符不得在一个函数的定义(8.4)一起使用,并且不得以DECL说明符-SEQ与任何其它种类的说明符的除外类型说明符进行组合。

类型定义名称:

标识符

...

在给定的范围内,可以使用 typedef 说明符重新定义在该范围内声明的任何类型的名称,以引用它已经引用的类型。[例子:

typedef struct s { /* ... */ } s;
typedef int I;
typedef int I;
typedef I I;

—结束示例]

§7.1.4 朋友说明符 [dcl.friend]

友元说明符用于指定对类成员的访问;见 11.4。

§7.1.5 类型说明符 [dcl.type]

类型说明符:

简单类型说明符

类说明符

枚举说明符

详细类型说明符

cv-限定符



Since §7 ?5 says that typedefnames come from the init-declaratorand the init-declarator-listis tagged 'opt', I think that means that the typedefname can be omitted in C++, just as in C.

由于 §7 ?5 说typedef名称来自init-declarator并且init-declarator-list被标记为“ opt”,我认为这意味着typedef在 C++ 中可以省略名称,就像在 C 中一样。

回答by Xeo

The only thing I could find was the following in the C++03 standard §7.1.3 [dcl.typedef] p1:

我唯一能找到的是 C++03 标准中的以下内容§7.1.3 [dcl.typedef] p1

typedef-name:

  • identifier

A name declared with the typedefspecifier becomes a typedef-name.

类型定义名称:

  • 标识符

使用说明typedef符声明的名称成为typedef-name

Notice the missing optafter identifier, which indicates, atleast to me, that an identifieris needed for the typedef-name. Strange that all tested compilers (silently) accept this.

请注意identifier之后缺少的opt,至少对我而言,这表明typedef-name需要一个标识符。奇怪的是,所有经过测试的编译器(默默地)都接受了这一点。



Edit: After @Jonathan's answer, I found the following in the same standard as above:

编辑:在@Jonathan 的回答之后,我在与上述相同的标准中发现了以下内容:

decl-specifier:

  • storage-class-specifier
  • type-specifier
  • function-specifier
  • friend
  • typedef

声明说明符

  • 存储类说明符
  • 类型说明符
  • 功能说明符
  • friend
  • typedef

As can be seen, it provides an extra case for typedefand the list on storage-class-specifiersconfirms this:

可以看出,它提供了一个额外的案例,typedef并且storage-class-specifiers上的列表证实了这一点:

storage-class-specifier:

  • auto
  • register
  • static
  • extern
  • mutable

存储类说明符:

  • auto
  • register
  • static
  • extern
  • mutable

So, we're just as clueless as before in the C++ case.

所以,在 C++ 的情况下,我们就像以前一样一无所知。

回答by luser droog

It really looks like a C vs. C++ difference, to me. C++ implicitly typedefs structs and unions to their tags; so adding the typedef is superfluous, but not an error. I don't know if this works for enums as well.

对我来说,它真的看起来像是 C 与 C++ 的区别。C++ 隐式地将结构体和联合体定义为它们的标签;所以添加 typedef 是多余的,但不是错误。我不知道这是否也适用于枚举。

The thing to do next is to see what variable definitions are permitted after these declarations.

接下来要做的是查看在这些声明之后允许哪些变量定义。

enum test etest;
test etest2;
struct named snamed;
named snamed2;