我来自一个php背景,我正在研究这个页面http://cocoadevcentral.com/articles/000081.php,然后再深入探讨一些关于objective-c的更难的东西
如果我输入类似这样的内容
typedef struct {
int lengthInSeconds;
int yearRecorded;
} Song;
当设置Song类型的函数或变量时,它是什么意思?我知道通过将函数设置为int或者浮点数,输出将与其类型集相关。但是当我做这样的事情时
Song myvariable;
or
Song myfunction(int params) { }
what type is Song setting?
感谢
答案 0 :(得分:15)
我认为它可以帮助您最大程度地了解编译器的主要内容。使用您的示例:
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
有一个独立的命名空间...所以语言中没有任何内容可以保证struct Song
和Song
是同一个东西!我不知道Objective C是否保持这种精神错乱,但我敢打赌它确实是安全的。
第二件事是你将这个匿名结构喂给typedef
。 typedef
只需要一种类型并为其定义一个名称,以便稍后使用。所以你真的在说“Song
是我刚宣布的struct {...}
的别名。”
通过typedef
Song
,您可以改为:
Song* GetSongInfo(const char* songName);
(是的,我知道最好返回const Song*
,但这不是重点。)
您可能会感兴趣的是,C在其标准库中有许多typedef,旨在将平台的细节与C标准的细节分开。例如,<unistd.h>
定义size_t
,表示大小的整数类型(并且是内置sizeof()
函数的返回类型),并且通过扩展,您应该传递的类型像malloc()
这样的函数。还有最近的<stdint.h>
标题,它按位大小定义整数类型,例如: uint8_t
表示8位无符号整数。 <stdint.h>
中的行可能看起来像:
typedef unsigned char uint8_t;
由于大多数平台都有8位字符。 (我已经针对像TI DSP这样的平台进行了编程,其中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);
这是一种情况,其中两条线可以比一条线快。
我可能错过了一些事情,让我知道这是否有意义......
答案 1 :(得分:2)
假设Objective 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;
}
(Jut说明该功能可以做任何事情......
答案 2 :(得分:2)
在第一种情况下:
Song myvariable;
您声明myvariable是您在typedef中声明的结构的实例。
在第二种情况下:
Song myfunction(int params) { }
你声明一个函数接受一个整数,并返回一个Song。由于花括号中没有代码,因此实际上并没有返回任何代码,编译器会在代码中报告错误。
答案 3 :(得分:1)
这是关于C结构的维基百科文章。
http://en.wikipedia.org/wiki/Struct_%28C_programming_language%29