帮助理解typedef结构

Sar*_*nHB 2 c objective-c

我来自php背景,我正在研究这个页面http://cocoadevcentral.com/articles/000081.php之后我进入了一些关于objective-c的更难的东西

如果我输入这样的东西

typedef struct { 
int lengthInSeconds; 
int yearRecorded; 
} Song; 
Run Code Online (Sandbox Code Playgroud)

当设置Song类型的函数或变量时,它是什么意思?我知道通过将函数设置为int或者浮点数,输出将与其类型集相关.但是当我做这样的事情

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

what type is Song setting?
Run Code Online (Sandbox Code Playgroud)

谢谢

Mik*_*one 15

我认为它可以帮助你最大程度地了解编译器头脑中发生了什么.使用你的例子:

typedef struct { 
int lengthInSeconds; 
int yearRecorded; 
} Song;
Run Code Online (Sandbox Code Playgroud)

实际上这里发生了两件事.首先是你要定义一个匿名的struct:

struct { 
int lengthInSeconds; 
int yearRecorded; 
}
Run Code Online (Sandbox Code Playgroud)

这种匿名struct可以在任何类型(例如int或者const char*)可以使用的地方使用.以下示例实际上是有效的,但是没有人应该编写这样的代码,因为这是一个维护噩梦:

struct { 
int lengthInSeconds; 
int yearRecorded; 
}* GetSongInfo(const char* songName);
Run Code Online (Sandbox Code Playgroud)

这声明了一个函数,它获取具有给定名称的歌曲的信息(假设名称是唯一的,在现实生活中是无效的假设)并返回指向struct具有其元数据的a的指针.

我将其称为"匿名struct",因为命名的结构形式如下所示:

struct Song { 
int lengthInSeconds; 
int yearRecorded; 
}
Run Code Online (Sandbox Code Playgroud)

现在你可以按名称引用那个结构,但不是你认为来自C以外语言的方式! 具体来说,上面的函数现在将声明为:

struct Song* GetSongInfo(const char* songName);
Run Code Online (Sandbox Code Playgroud)

请注意,类型名称struct Song不仅仅是Song!事实上,structs有一个独立的命名空间...所以语言中没有任何东西可以保证struct Song并且Song是同一个东西! 我不知道Objective C是否保持这种精神错乱,但我敢打赌它确实是安全的.

第二件事是你正在喂这个匿名结构typedef. typedef只需要一种类型,并为它定义一个您可以在以后使用的名称.所以你真的说"a Songstruct {...}我刚宣布的别名."

通过typedefing Song,您可以改为:

Song* GetSongInfo(const char* songName);
Run Code Online (Sandbox Code Playgroud)

(是的,我知道返回会更好const Song*,但那不是重点.)

您可能会感兴趣的是,C在其标准库中有许多typedef,旨在将平台的细节与C标准的细节分开.例如,<unistd.h>define size_t,表示大小的整数类型(并且是内置sizeof()函数的返回类型),以及扩展名,应传递给函数的类型malloc().还有最近的<stdint.h>头,它按位的大小定义整数类型,例如uint8_t,对于8位无符号整数.该行<stdint.h>可能看起来像:

typedef unsigned char uint8_t;
Run Code Online (Sandbox Code Playgroud)

由于大多数平台都有8位字符.(我已经针对某些平台进行了编程,例如TI DSP,其中a char不是8位;通常它是16,因为处理器无法访问部分字.但是我们暂时忽略退化平台.)

最后,解释一下你的例子:

Song myvariable;
Run Code Online (Sandbox Code Playgroud)

这声明了Song结构的存储.如果它在函数定义中,则该存储将在堆栈上分配,并在函数终止时释放.如果它在函数定义之外,它将被分配为全局.在任何一种情况下,它都是未初始化的,在C中它意味着它可以包含任何随机值.C不会跟踪未初始化的变量或将它们设置为"未初始化"或PHP和Python之类的任何变量.C也不会抛出异常.

Song myfunction(int params) { }
Run Code Online (Sandbox Code Playgroud)

这定义了一个取整数并返回Song结构的函数.该return函数的声明必须给出一个Song.例如:

Song myfunction(int params)
{
    Song result;
    result.lengthInSeconds = GetSongLength(params); 
    result.yearRecorded = GetSongYear(params); 
    return result;
}
Run Code Online (Sandbox Code Playgroud)

此函数在堆栈上为a分配空间Song,通过调用返回ints的函数填充其字段,然后return将结构复制result到为返回值保留的空间中,最后result在函数结束时释放存储for .通常,编译器可以优化return语句中隐含的副本.此外,可能存在从返回值存储到最终目标的另一个(可能是优化的)副本,例如当您说:

Song foundSongInfo = myfunction(params);
Run Code Online (Sandbox Code Playgroud)

顺便说一句,struct在堆栈上返回s是不受欢迎的,因为如果返回值适合寄存器(即简单类型),编译器通常可以更好地优化.(C++中有例外的运算符重载,但这是偏离主题的.)更好的定义是:

void myfunction(int params, Song* found)
{
    found->lengthInSeconds = GetSongLength(params); 
    found->yearRecorded = GetSongYear(params); 
}
Run Code Online (Sandbox Code Playgroud)

这避免了所有额外的副本.你这样称呼它:

Song foundSongInfo;
myfunction(params, &foundSongInfo);
Run Code Online (Sandbox Code Playgroud)

这是一种情况,其中两条线可以比一条线快.

我可能错过了一些事情,让我知道这是否有意义......