2010-01-02 109 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