我认为这会帮助您最了解编译器头上正在发生的事情。用你的例子:
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