关于返回结构体的函数

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

(一)不超过8 bytes 的小结构体可以通过EDX:EAX 返回。

本文的范例代码取材于《汇编中函数返回结构体的方法》一文,并在此基础上进行修改和试验。要研究的第一份代码如下,定义一个不超过8 bytes 的小结构体,不超过8 bytes 是因为这个结构体能够用EDX:EAX 容纳,我们之后将看到在release 编译时,编译器能够向返回普通基础类型那样进行返回。

#include

//不超过 8 bytes 的“小结构体”

struct A

{

int a;

int b;

};

//返回结构体的函数

struct A add(int x, int y)

{

struct A t;

t.a = x * y;

return t;

}

int main()

{

struct A t = add(3, 4);

printf("t.a = %ld\n", t.a);

return0;

}

首先,我们需要解决一个常见困惑,就是要明确这段代码和下面的典型错误代码的区别:char* get_buffer()

{

char buf[8];

return buf;

}

上面的get_buffer 返回的是栈上的临时变量空间,在函数返回后,其所在的空间也就被“回收/释放”了,也就是说函数返回的地址位于栈的增长方向上,是不稳定和不被保证的。

那么返回结构体的函数则不同,你可以发现返回结构体的函数是工作正常有效的。在add 函数中有一个临时性结构体t,毫无疑问,t 将在add 函数返回时被释放,但由于t 被当做“值”进行返回,因此编译器将保证add 的返回值对于add 的调用者(caller)来说是有效的。

另外需要明确的一点是,我个人觉得,现实里这种返回结构体的方式比较少见,后面将会看到这样做会产生临时对象和多余拷贝过程,效率不高。常见方法是传递结构体指针。但作为语言上允许的方式,有必要弄清楚编译器如何实现这种方式,而要弄清楚这个问题,需要查看汇编代码。使用VC6 输入上述代码,下面分别给出其汇编代码。

(1)debug 版本,汇编代码如下。

small_struct_debug

下面是实现方式的栈示意图:

总结:

(1.1)用edx:eax 传递返回值。调用方不需要在栈上向add 函数传递接受返回值的地址。

(2.2)debug 版本在调用方生成临时对象返回值,然后再把临时对象拷贝到main 临时变量所在地址。效率低。

(2)release 版本,汇编代码如下:

small_struct_release

总结:

(2.1)同(1.1),用edx:eax 传递返回值,不需要传递接收返回值的地址。

(2.2)release 版本调用方没有临时对象,效率基本等同于传结构体指针。

(2.3)release 版本优化的太厉害,甚至都没有把返回值完整的拷贝到临时变量t (只拷贝了结构体中的成员t.b,t.a 的拷贝被认为没有存在价值而被优化掉了,因为t.a 的值存于eax),和高级语言有较大差别。

相关文档
最新文档