帮助理解typedef结构

时间:2010-01-02 03:27:51

标签: c objective-c

我来自一个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?

感谢

4 个答案:

答案 0 :(得分: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有一个独立的命名空间...所以语言中没有任何内容可以保证struct SongSong是同一个东西!我不知道Objective C是否保持这种精神错乱,但我敢打赌它确实是安全的。

第二件事是你将这个匿名结构喂给typedeftypedef只需要一种类型并为其定义一个名称,以便稍后使用。所以你真的在说“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