2014-06-15 109 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;