名称在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
是官方(或语法上)“存储类说明符”,如static
, extern
, auto
和register
。
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