2010-01-02 82 views
2

我來自一個PHP的背景和正在學習此頁http://cocoadevcentral.com/articles/000081.php之前,我踏上到一些更強硬的東西在關於Objective-C的幫助理解typedef結構

如果鍵入像這樣

typedef struct { 
int lengthInSeconds; 
int yearRecorded; 
} Song; 

當設置一個功能或類型宋的變量,這是什麼意思?我明白,通過設置一個函數作爲一個int或可能是一個浮動輸出將與其類型集有關。但是當我做這樣的事情

Song myvariable; 
or 
Song myfunction(int params) { } 

what type is Song setting? 

感謝

回答

1

這是基於C的結構維基百科文章。

http://en.wikipedia.org/wiki/Struct_%28C_programming_language%29

+0

我閱讀了維基百科的文章。但不明白它的目的,它會類似於在PHP中編寫類? – SarmenHB 2010-01-02 03:37:57

+0

結構與類相似,它們將其他幾個變量(在本例中爲兩個整數)分組爲一個自包含的數據包(請參閱NSResponder和lpthnc的其他答案)。不過,C結構和PHP類的意識形態卻非常不同。 – 2010-01-02 03:40:45

2

假設目標C是非常接近C,你做到這一點:

Song myvariable; // creates the truct in memory 
myvariable.lengthInSeconds = 10; 
myvariable.yearRecorded = 2010; 

我不能說的功能是什麼,因爲你沒有給它IMPL。

這裏是你如何解決這個功能做一些「有用」:

Song myfunction(int params) { 
    Song ret; 
    ret.lengthInseconds = params * 69; 
    ret.yearRecorded = 3*5*7*9*11; 
    return ret; 
} 

(突出部分來說明該功能可以爲所欲爲......

2

在第一種情況:

Song myvariable; 

您聲明myvariable是您在typedef中聲明的結構的一個實例。

在第二種情況下:

Song myfunction(int params) { } 

您聲明的函數只接受一個整數並返回一個樂曲。由於花括號中沒有代碼,因此實際上並沒有返回任何內容,編譯器會在代碼中報告錯誤。

+0

我只是補充說第一種意思是「保留足夠的內存空間來容納一個類型爲Song的結構並將其命名爲myvariable」,而第二種意思是:「我保證這個函數將返回一個類型爲Song的結構」。 – 2010-01-02 07:47:13

15

我認爲這會幫助您最瞭解編譯器頭上正在發生的事情。用你的例子:

typedef struct { 
int lengthInSeconds; 
int yearRecorded; 
} Song; 

實際上有兩件事發生在這裏。第一個是你定義一個匿名struct

struct { 
int lengthInSeconds; 
int yearRecorded; 
} 

這個匿名struct可以在任何地方使用的類型(例如intconst 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是否會維持這種瘋狂狀態,但我敢打賭它確實是安全的。

第二件事是你將這個匿名結構餵給typedeftypedef只需要一種類型,併爲其定義一個名稱,以便以後使用。所以你真的說「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); 

這是兩行可能比一行快的情況。

我可能錯過了一些事情,讓我知道如果這是有道理的...

+0

我在StackOverflow上見過的最佳答案之一。謝謝! – 2013-12-03 22:23:40