2014-06-15 71 views
54

我已经在现有的代码中的以下(工作)的代码,在使用包括被C和C++之间共享文件,在MSVC(2010)和Windows DDK编译:'struct X typedef`与`typedef struct X`是什么意思?

struct X { 
    USHORT x; 
} typedef X, *PX; 

和:

enum MY_ENUM { 
    enum_item_1, 
    enum_item_2 
} typedef MY_ENUM; 

据我所知,正确的定义应该是这样的:

typedef struct { 
    USHORT x; 
} X, *PX; 

有什么目的的,其具有以下形式?我错过了什么吗?

回答

56

两个typedef <type> <alias><type> typedef <alias>是有效的简单事实来自语言语法定义。

typedef被归类为存储类specfifier(就像staticauto),并且类型本身是已知的作为类型说明符。从标准的6.7节的语法定义,你会发现这些都是免费进行互换:

declaration: 
    declaration-specifiers init-declarator-list ; 

declaration-specifiers: 
    storage-class-specifier declaration-specifiers 
    type-specifier declaration-specifiers 
    type-qualifier declaration-specifiers 
    function-specifier declaration-specifiers 

init-declarator-list: 
    init-declarator 
    init-declarator-list , init-declarator 

init-declarator: 
    declarator 
    declarator = initializer 

(注意,当然,这是同样真实的结构和非结构,这意味着那double typedef trouble;也是有效的。)

6

两者具有相同的含义。无论这两种形式是有效的:

typedef <existing_type> <new_type> 
<existing_type> typedef <new_type> 

可以typedef上述结构以两种方式:

struct X { 
    USHORT x; 
}typedef X, *PX;  // <existing_type> typedef <new_type> 

typedef struct { 
    USHORT x; 
} X, *PX;   // typedef <existing_type> <new_type> 
+2

难道不应该永远是 “typedef的”?这是结构的特殊扩展吗? – Itaypk

+0

@Itaypk不仅仅是结构体,你可以从你的'enum'例子中看到。 –

+0

@Itaypk;不是。它不是扩展名。查看编辑。 – haccks

5

你真的被允许把你想要的任何顺序的所有声明说明符!任何*指针的位置和实际的声明者(变量或新类型名称)的问题,但所有typedefintunsignedconststatic等东西可以以任何顺序。

如果你看看C的官方语法,它只是说:

declaration: 
    declaration-specifiers init-declarator-list ; 

declaration-specifiers是所有存储类型说明符(typedefextern等),类型说明符(实际的类型,如intstruct X),类型限定符(constvolatile)以及其他一些不常见的。他们的顺序并不重要。第二部分是init-declarator-list,它是变量或新类型名称(在typedef的情况下),任何*字符,变量的初始化(int x = 3)等等。声明符部分中的事物顺序很重要,但不是声明说明符中的顺序。

18

正如其他人所说,typedef是一个存储类说明符,与其他存储类说明符一样,您也允许将说明符放在类型和声明程序之间。

虽然这是有效的,但也应避免为C标记它作为一个过时的特征的一种形式:

(C11,6.11.5p1)“以外的存储类说明的放置比声明中的声明说明符的开头部分是过时的特征。“

5

声明:这不是一个技术性的,而是一个实际的答案。有关技术问题,请参阅其他答案。这个答案读取的是自以为是和主观的,但请在我试图解释更大的图片时忍受。

struct是一个奇怪的野兽,因为你的右括号}和分号;之间放的东西是指里面的内容还是那些括号之前。我知道这是为什么,和语法也有一定道理,但我个人觉得非常反直觉的大括号通常是指范围:

反直观的例子:

// declares a variable named `foo` of unnamed struct type. 
struct { 
    int x, y; 
} foo; 

foo.x = 1; 


// declares a type named `Foo` of unnamed struct type 
struct { 
    int x, y; 
} typedef Foo; 

Foo foo2; 
foo2.x = 2; 


// declares a type named `Baz` of the struct named `Bar` 
struct Bar { 
    int x, y; 
} typedef Baz; 

// note the 'struct' keyword to actually use the type 'Bar' 
struct Bar bar; 
bar.x = 3; 
Baz baz; 
baz.x = 4; 

有这么如果以这种方式使用,可能会出现许多细微的问题,如密码语法structtypedef。如下所示,非常容易声明一个变量而不是偶然类型。编译器只有有限的帮助,因为几乎所有的组合都是语法正确的。他们并不一定表示你想表达的内容。这是一个pit of despair

错误示例:

// mixed up variable and type declaration 
struct foo { 
    int x, y; 
} Foo; 

// declares a type 'foo' instead of a variable 
typedef struct Foo { 
    int x, y; 
} foo; 

// useless typedef but compiles fine 
typedef struct Foo { 
    int x, y; 
}; 

// compiler error 
typedef Foo struct { 
    int x, y; 
}; 

出于可读性和维护的原因,我更喜欢单独声明一切,从不把右花括号后面的东西。直观的语法轻易超过额外代码行的成本。我认为这种做法makes it easy to do the right things and annoying to do the wrong things

直观的例子:

// declares a struct named 'TVector2' 
struct TVector2 { 
    float x, y; 
}; 

// declares a type named 'Vector2' to get rid of the 'struct' keyword 
// note that I really never use 'TVector2' afterwards 
typedef struct TVector2 Vector2; 

Vector2 v, w; 
v.x = 0; 
v.y = 1;