C中这两种typedef样式有什么区别?

Kev*_*lar 12 c typedef objective-c

我很好奇当typedefing一个枚举或结构时,这里的区别是什么.这两个块之间在语义上有什么区别吗?

这个:

typedef enum { first, second, third } SomeEnum;
Run Code Online (Sandbox Code Playgroud)

还有这个:

enum SomeEnum { first, second, third };
typedef enum SomeEnum SomeEnum;
Run Code Online (Sandbox Code Playgroud)

结构相同的交易.我已经看到两者都在使用,他们似乎都在C或Objective-C中做同样的事情.是否存在真正的差异,或者只是偏好您可以使用哪种风格?

AnT*_*AnT 15

不同之处在于第二种方法声明了一个名为的类型,enum SomeEnum并且还声明了一个typedef-name SomeEnum- 该类型的别名.它实际上可以组合成等效的单行程

typedef enum SomeEnum { first, second, third } SomeEnum;
Run Code Online (Sandbox Code Playgroud)

这很明显,两种方法之间的唯一区别在于enum关键字后面是否有名称.使用第二种方法,您可以使用SomeEnum e或者enum SomeEnum e,无论您喜欢哪种方式声明该枚举类型的对象.

第一种方法仅为SomeEnum最初的匿名枚举类型声明typedef-name ,这意味着您仅限于SomeEnum e声明.

因此,只要您SomeEnum在声明中仅使用typedef-name ,两者之间就没有区别.但是,在某些情况下,您可能必须使用该类型的完整原始名称enum SomeEnum.在第一种方法中,该名称不可用,因此您将失去运气.

例如,如果在上述声明之后,您还声明了SomeEnum在某个嵌套范围中命名的变量

int SomeEnum;
Run Code Online (Sandbox Code Playgroud)

变量的名称将隐藏枚举的typedef-name,从而使此声明非法

SomeEnum e; /* ERROR: `SomeEnum` is not a type */
Run Code Online (Sandbox Code Playgroud)

但是,如果在声明枚举时使用第二种方法,则可以使用完整类型名称解决此问题

enum SomeEnum e; /* OK */
Run Code Online (Sandbox Code Playgroud)

如果在声明枚举类型时使用第一种方法,则无法实现这一点.

当与结构一起使用时,struct当你需要一个自引用类型(一个包含指向同一类型的指针的类型)时,必须使用该名称,例如

typedef struct SomeStruct {
  struct SomeStruct *next;
} SomeStruct;
Run Code Online (Sandbox Code Playgroud)

最后,在第二种方法中,typedef名称是完全可选的.你可以简单地宣布

enum SomeEnum { first, second, third };
Run Code Online (Sandbox Code Playgroud)

并且只需在enum SomeEnum每次需要引用此类型时使用.


Joh*_*itb 7

是的,存在语义差异.第二个片段声明了标记标识符,但第一个标识符没有.两者都声明一个普通的标识符.

这意味着,对于第一个,此代码无效,但对于第二个,它是:

enum SomeEnum foo;
Run Code Online (Sandbox Code Playgroud)

据我所知,代码中它们之间没有其他语义差异.对于结构和联合,递归类型需要第二种形式,可能与一个声明中的typedef结合使用

typedef struct node {
  struct node *parent; // refer to the tag identifier
} node;
Run Code Online (Sandbox Code Playgroud)

普通标识符在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 {
  /* ... */
};
Run Code Online (Sandbox Code Playgroud)

Typedef名称不能在同一范围内重复声明(与C++相反),并且它们需要引用现有类型,因此它们不能用于创建前向声明.