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
Is the typedef-name optional in a typedef declaration?
提问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 typedef
keyword 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 typedef
is 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 typedef
is officially (or syntactically) a 'storage class specifier', like static
, extern
, auto
and register
.
请注意,typedef
是官方(或语法)一个“存储类说明”,如static
,extern
,auto
和register
。
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 typedef
as a storage class; the list adds mutable
and excludes typedef
. So, the grammatical specification of typedef
in C++ is definitely different from the C specification.
在 ISO/IEC 14882:1998(原始 C++ 标准)中,我们在第 7.1.1 节“存储类说明符”中发现 C++ 不将其typedef
视为存储类;该列表添加mutable
和排除typedef
. 所以,typedef
C++中的语法规范与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
typedef
specifier, the declaration is called atypedef
declaration and the name of eachinit-declarator
is 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
typedef
declare identifiers that can be used later for naming fundamental (3.9.1) or compound (3.9.2) types. Thetypedef
specifier 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 typedef
names come from the init-declaratorand the init-declarator-listis tagged 'opt', I think that means that the typedef
name 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
typedef
specifier 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 typedef
and 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;