[英]What are the differences between these two typedef styles in C?
我很好奇当typedefing一个枚举或结构时,这里的区别是什么。 这两个块之间在语义上有什么区别吗?
这个:
typedef enum { first, second, third } SomeEnum;
还有这个:
enum SomeEnum { first, second, third };
typedef enum SomeEnum SomeEnum;
结构相同的交易。 我已经看到两者都在使用,他们似乎都在C或Objective-C中做同样的事情。 是否存在真正的差异,或者只是偏好您可以使用哪种风格?
不同之处在于第二种方法声明了一个名为enum SomeEnum
的类型,并且还声明了一个typedef-name SomeEnum
- 该类型的别名。 它实际上可以组合成等效的单行程
typedef enum SomeEnum { first, second, third } SomeEnum;
这很明显,两种方法之间的唯一区别是enum
关键字后面是否有名称。 使用第二种方法,您可以使用SomeEnum e
或enum SomeEnum e
(无论您喜欢哪种方式)声明该枚举类型的对象。
第一种方法仅为最初的匿名枚举类型声明typedef-name SomeEnum
,这意味着您仅限于SomeEnum e
声明。
因此,只要您在声明中仅使用typedef-name SomeEnum
,两者之间就没有区别。 但是,在某些情况下,您可能必须使用类型enum SomeEnum
的完整原始名称。 在第一种方法中,该名称不可用,因此您将失去运气。
例如,如果在上述声明之后,您还在某个嵌套范围中声明了名为SomeEnum
的变量
int SomeEnum;
变量的名称将隐藏枚举的typedef-name,从而使此声明非法
SomeEnum e; /* ERROR: `SomeEnum` is not a type */
但是,如果在声明枚举时使用第二种方法,则可以使用完整类型名称解决此问题
enum SomeEnum e; /* OK */
如果在声明枚举类型时使用第一种方法,则无法实现这一点。
当与结构一起使用时,当你需要一个自引用类型(一个包含指向同一类型的指针的类型)时, struct
之后的名称是必须的,比如
typedef struct SomeStruct {
struct SomeStruct *next;
} SomeStruct;
最后,在第二种方法中,typedef名称是完全可选的。 你可以简单地宣布
enum SomeEnum { first, second, third };
每次需要引用此类型时,只需使用enum SomeEnum
。
是的,存在语义差异。 第二个片段声明了标记标识符,但第一个标识符没有。 两者都声明一个普通的标识符。
这意味着,对于第一个,此代码无效,但对于第二个,它是:
enum SomeEnum foo;
据我所知,代码中它们之间没有其他语义差异。 对于结构和联合,递归类型需要第二种形式,可能与一个声明中的typedef结合使用
typedef struct node {
struct node *parent; // refer to the tag identifier
} node;
普通标识符在struct的说明符中尚不可见,因此您需要通过已声明的标记标识符来引用该结构。 标签标识符通过在“struct”,“union”或“enum”之前加上它们来引用,而普通标识符在没有前缀的情况下引用(因此名称为“普通”)。
除了将引用结构,联合和枚举的标识符与引用值的标识符分开时,标记标识符对于创建前向声明也很有用:
/* forward declaration */
struct foo;
/* for pointers, forward declarations are entirely sufficient */
struct foo *pfoo = ...;
/* ... and then later define its contents */
struct foo {
/* ... */
};
Typedef名称不能在同一范围内重复声明(与C ++相反),并且它们需要引用现有类型,因此它们不能用于创建前向声明。
唯一真正的区别是,在第二种情况下,您可以使用以下内容:
enum SomeEnum x;
而第一个只支持:
SomeEnum x;
人谁已经用C写很长的时间,定义一个struct
没有struct
往往关键词“感觉”奇怪...
第一个表单创建一个匿名enum
类型并SomeEnum
创建一个SomeEnum
别名。
第二种形式创建enum SomeEnum
类型和SomeEnum
别名。
(在C中,类型有单独的命名空间。也就是说, struct Foo
与enum Foo
不同,它与Foo
不同。)
对于struct
这比enum
更重要,因为如果你的struct
是自引用的,你需要使用第二种形式。 例如:
struct LinkedListNode
{
void* item;
struct LinkedListNode* next;
};
typedef struct LinkedListNode LinkedListNode;
第一种形式无法实现上述目标。
对于struct
真正的区别不仅仅在于命名。
这是有效的C:
struct SomeEnum { struct SomeEnum *first; };
这不是:
typedef struct { SomeEnum *first; } SomeEnum;
having a definition for the struct. 添加到user207442的评论,有可能为源代码模块,而为结构的定义声明式“结构FOO *”的变量。 这样的模块将无法取消引用这样的指针,但可以将它们传递给其他模块或从其他模块传递。
例如,可以使用“typedef struct _USERCONSOLE * USERCONSOLE;”来为头文件定义类型“USERCONSOLE”。 代码表示#include的头文件可以包含USERCONSOLE类型的变量,并将这些变量传递给/来自知道_USERCONSOLE实际是什么的模块,而头文件不必暴露结构的实际定义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.