我認爲這會幫助您最瞭解編譯器頭上正在發生的事情。用你的例子:
typedef struct {
int lengthInSeconds;
int yearRecorded;
} Song;
實際上有兩件事發生在這裏。第一個是你定義一個匿名struct
:
struct {
int lengthInSeconds;
int yearRecorded;
}
這個匿名struct
可以在任何地方使用的類型(例如int
或const char*
)都可以使用。下面的例子實際上是有效的,但沒有人應該永遠像這樣寫代碼,因爲它是一個維護的噩夢:
struct {
int lengthInSeconds;
int yearRecorded;
}* GetSongInfo(const char* songName);
這個聲明具有給定名稱獲取信息的一首歌(假設名稱是唯一的,一個功能在現實生活中無效假設)並返回一個指向struct
及其元數據的指針。
我提到,作爲一個「匿名struct
」,因爲命名的結構形式如下:
struct Song {
int lengthInSeconds;
int yearRecorded;
}
現在,您可以參考該結構的名字,但不是在時尚你會覺得未來從C以外的語言!具體來說,上面的功能現在將被聲明爲:
struct Song* GetSongInfo(const char* songName);
注意,該類型名稱是struct Song
並不僅僅是Song
!事實上,struct
s擁有自己的獨立命名空間......所以沒有任何語言可以保證struct Song
和是同一件事情!我不知道Objective C是否會維持這種瘋狂狀態,但我敢打賭它確實是安全的。
第二件事是你將這個匿名結構餵給typedef
。 typedef
只需要一種類型,併爲其定義一個名稱,以便以後使用。所以你真的說「Song
是我剛剛宣佈的那個struct {...}
的別名。」
通過typedef
荷蘭國際集團Song
,可以改爲寫:
Song* GetSongInfo(const char* songName);
(是的,我知道這將是更好的回報const Song*
,但那是題外話。)
可能感興趣的你注意C在其標準庫中有許多類型定義,旨在將平臺的細節與C標準的細節分開。例如,<unistd.h>
定義了size_t
,這是表示大小(並且是內置sizeof()
函數的返回類型)的整數類型,以及擴展後,您應該傳遞給像malloc()
這樣的函數的類型。還有最近的<stdint.h>
標題,它通過它們的大小以位爲單位來定義整數類型,例如,對於8位無符號整數,爲uint8_t
。在<stdint.h>
行可能看起來像:
typedef unsigned char uint8_t;
由於大多數平臺上有8位字符。 (我已經爲TI DSPs編寫了一些平臺,其中char
不是8位;通常它是16,因爲處理器無法訪問部分文字,但我們暫時忽略退化平臺)。最後,說明你的例子:
Song myvariable;
這爲Song
結構宣稱存儲。如果它在函數定義中,那麼該存儲將被分配到堆棧上並在函數終止時被釋放。如果它在函數定義之外,它將被分配爲全局。無論哪種情況,它都將被初始化,這在C中意味着它可以包含任何隨機值。 C沒有跟蹤未初始化的變量,或者將它們設置爲「未初始化」,或者像PHP和Python那樣。 C也不會拋出異常。
Song myfunction(int params) { }
這定義了一個函數,它需要一個整數並返回一個Song
結構。該函數的return
聲明必須給出Song
。例如:
Song myfunction(int params)
{
Song result;
result.lengthInSeconds = GetSongLength(params);
result.yearRecorded = GetSongYear(params);
return result;
}
該函數的堆棧一個Song
上分配空間,填充在其字段中通過調用返回int
s,則return
複製結構result
到用於返回值保留的空間的功能,並且最後功能結束時釋放result
的存儲空間。通常,編譯器可以優化return
語句中隱含的副本。另外,還有可能是另一個(可能優化)從返回值的存儲複製到最終目的地,例如,當你說:
Song foundSongInfo = myfunction(params);
順便說一句,在堆棧上返回struct
小號是不可取的,因爲編譯器如果返回值適合寄存器(即簡單類型),通常可以更好地優化。 (這在C++例外運算符重載,但這是題外話。)一個更好的定義是:
void myfunction(int params, Song* found)
{
found->lengthInSeconds = GetSongLength(params);
found->yearRecorded = GetSongYear(params);
}
這樣就避免了所有的額外副本。你這樣稱呼它:
Song foundSongInfo;
myfunction(params, &foundSongInfo);
這是兩行可能比一行快的情況。
我可能錯過了一些事情,讓我知道如果這是有道理的...
我閱讀了維基百科的文章。但不明白它的目的,它會類似於在PHP中編寫類? – SarmenHB 2010-01-02 03:37:57
結構與類相似,它們將其他幾個變量(在本例中爲兩個整數)分組爲一個自包含的數據包(請參閱NSResponder和lpthnc的其他答案)。不過,C結構和PHP類的意識形態卻非常不同。 – 2010-01-02 03:40:45