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

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

typedef enum test { one };

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

typedef enum test { one } test;

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

我一直无法确定这个标准允许在哪里,我发现有两个编译器警告它是必需的,如果typedef-name是必需的但不存在,它不应该是一个错误吗?

更新 :我用相同的编译器检查了C语言。 Clang和comeau产生相同的输出,gcc给出了一个警告:“警告:在空声明中无用的存储类说明符”,这看起来更加混乱。

更新 :我检查删除枚举的名称和结果是相同的:

typedef enum { one };

与命名结构类似:

typedef struct named { int x };

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


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

enum test { one };

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

typedef struct SomeThing { int whatever; };

这相当于:

struct SomeThing { int whatever; };

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


C标准

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

§6.7声明

句法

宣言:

声明指定符init-declarator-listopt;

声明-符:

存储类说明符声明-specifiersopt

类型说明符声明-specifiersopt

类型 - 限定符声明 - specifiersopt

函数说明符声明-specifiersopt

初始化声明符列表:

初始化声明符

init-declarator-list,init-declarator

初始化声明符:

声明符

声明器=初始化器

并且(根据要求):

§6.7.1存储类说明符

句法

存储类说明符:

typedef

extern

static

auto

register

如果你通过这种语法来追踪,那么很多退化的可能性,你展示的只是其中的一个。


C ++标准

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

在ISO / IEC 14882:1998(最初的C ++标准)中,我们在§7.1.1'存储类说明符'中发现C ++不会将typedef视为存储类; 该列表添加了mutable并排除了typedef 。 所以,C ++中的typedef的语法规范明显不同于C规范。

§7声明

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

声明-SEQ:

宣言

声明-seq声明

宣言:

块声明

函数的定义

模板声明

显式实例化

明确的分工

联动规范

命名空间定义

块声明:

简单的声明

ASM-定义

命名空间别名定义

使用声明

使用指示符

简单的声明:

decl-specifier-seqopt init-declarator-listopt;

...

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

§7.1说明符[dcl.spec]

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

DECL说明符:

存储类说明符

类型说明符

功能说明符

friend

typedef

DECL说明符-SEQ:

DECL说明符,seqopt

DECL说明符

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

存储类说明符:

auto

register

static

extern

mutable

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

功能说明符:

inline

virtual

explicit

§7.1.3typedef说明符[dcl.typedef]

包含decl-specifier typedef声明声明了稍后可用于命名基本(3.9.1)或复合(3.9.2)类型的标识符。 typedef说明符不能用在函数定义(8.4)中,除了类型说明符之外,它不能在decl-specifier-seq中与任何其他类型的说明符结合使用。

typedef的名称:

识别码

...

在给定的范围内,可以使用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-预选赛


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


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

typedef的名称:

  • 识别码
  • 使用typedef说明符声明的名称将成为typedef名称。

    注意标识符后缺少的选项,至少表明typedef-name需要标识符。 奇怪的是,所有测试的编译器(无声)接受这一点。


    编辑 :在@乔纳森的回答后,我发现以下与上面相同的标准:

    DECL说明符:

  • 存储类说明符
  • 类型说明符
  • 功能说明符
  • friend
  • typedef
  • 可以看出,它为typedef提供了一个额外的情况,存储类说明符上的列表证实了这一点:

    存储类说明符:

  • auto
  • register
  • static
  • extern
  • mutable
  • 所以,在C ++的情况下,我们和以前一样无知。


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

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

    enum test etest;
    test etest2;
    struct named snamed;
    named snamed2;
    
    链接地址: http://www.djcxy.com/p/58709.html

    上一篇: name optional in a typedef declaration?

    下一篇: c++ template seems to break access specifiers