system888net 发表于 2008-06-09 23:09

结构体作为传递和返回值的小例子

当C用struct 传递并返回值也是struct 时,编译器是如何处理的哪,下面是gcc的处理方式.


#include <stdio.h>
#include <stdlib.h>
struct sa {
   int a;
   int b;
   char c;
};

struct sa fun1(struct sa psa)
{
   psa.a=1;
   psa.b=99;
   psa.c='a';
   return(psa);
}
struct sa ss;

int main()
{
   struct sa k;
   struct sa ll;
   k.a=11;
   k.b=12;
   k.c='0';
   ll=fun1(k);
   printf("%d,%d,%c",k.a,k.b,k.c);
   printf("hello,world!");
   printf("%d,%d,%c",ll.a,ll.b,ll.c);
   return(0);
}




gcc的处理方式,注意fun1中
        "movl        8(%ebp), %edx"
   和
"        movl        %edx, %eax"
   等几句.


        .file        "test5.c"
        .text
.globl fun1
        .type        fun1,@function
fun1:
        pushl        %ebp
        movl        %esp, %ebp
        movl        8(%ebp), %edx   //ll的地址保存到edx
        movl        $1, 12(%ebp)      //psa.a=1
        movl        $99, 16(%ebp)   //psa.b=99
        movb        $97, 20(%ebp)   //psa.c='a'
        movl        12(%ebp), %eax    //psa.a 放到eax寄存器,实际上在fun1内已经对main中ll进行赋值了.
        movl        %eax, (%edx)      //ll.a=psa.a
        movl        16(%ebp), %eax   
        movl        %eax, 4(%edx)   //ll.b=psa.b
        movl        20(%ebp), %eax
        movl        %eax, 8(%edx)   //ll.c=psa.c
        movl        %edx, %eax         //eax 存放ll的地址
        leave
        ret        $4
.Lfe1:
        .size        fun1,.Lfe1-fun1
        .section        .rodata
.LC0:
        .string        "%d,%d,%c"
.LC1:
        .string        "hello,world!"
        .text
.globl main
        .type        main,@function
main:
        pushl        %ebp
        movl        %esp, %ebp
        subl        $40, %esp    //本地变量空间
        andl        $-16, %esp   //对齐
        movl        $0, %eax
        subl        %eax, %esp
        movl        $11, -24(%ebp)//k.a=11
        movl        $12, -20(%ebp)//k.b=12
        movb        $48, -16(%ebp)//k.c='0'
        leal        -40(%ebp), %eax //ll的地址
        pushl        -16(%ebp)//k.c
        pushl        -20(%ebp)//k.b
        pushl        -24(%ebp)//k.a
        pushl        %eax//压入ll的地址,以便fun1能对其进行赋值
        call        fun1
        addl        $12, %esp
        movsbl        -16(%ebp),%eax
        pushl        %eax
        pushl        -20(%ebp)
        pushl        -24(%ebp)
        pushl        $.LC0
        call        printf
        addl        $16, %esp
        subl        $12, %esp
        pushl        $.LC1
        call        printf
        addl        $16, %esp
        movsbl        -32(%ebp),%eax
        pushl        %eax
        pushl        -36(%ebp)
        pushl        -40(%ebp)
        pushl        $.LC0
        call        printf
        addl        $16, %esp
        movl        $0, %eax
        leave
        ret
.Lfe2:
        .size        main,.Lfe2-main
        .comm        ss,12,4
        .ident        "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"


[ 本帖最后由 system888net 于 2008-6-11 11:23 编辑 ]

mnf 发表于 2008-06-09 23:46

你烦不烦的,C版说了不够,还要到这里贴

chzCPU 发表于 2008-06-09 23:54

原帖由 mnf 于 2008-6-9 23:46 发表 http://linux.chinaunix.net/bbs/images/common/back.gif
你烦不烦的,C版说了不够,还要到这里贴


谦虚使人进步

chzCPU 发表于 2008-06-10 00:04

原帖由 mnf 于 2008-6-9 23:46 发表 http://linux.chinaunix.net/bbs/images/common/back.gif
你烦不烦的,C版说了不够,还要到这里贴


............................................................

[ 本帖最后由 chzCPU 于 2008-6-10 00:18 编辑 ]

system888net 发表于 2008-06-10 00:08

:) 观点都是一样的,都是为了说明同一个问题.觉得有汇编更能说明stack和eax配合传递struct 的过程,而且感觉这个问题跟编译器有关,有必要在这个论坛也发一下.

[ 本帖最后由 system888net 于 2008-6-10 00:16 编辑 ]

mnf 发表于 2008-06-10 00:38

原帖由 system888net 于 2008-6-10 00:08 发表 http://linux.chinaunix.net/bbs/images/common/back.gif
:) 观点都是一样的,都是为了说明同一个问题.觉得有汇编更能说明stack和eax配合传递struct 的过程,而且感觉这个问题跟编译器有关,有必要在这个论坛也发一下.

:mrgreen: :mrgreen:很佩服你! 不但出动了马甲造势,还在C版沸沸扬扬忽悠人。
哈哈~ 你好样的。 继续~~ 兄弟看着你

mnf 发表于 2008-06-10 00:40

原帖由 chzCPU 于 2008-6-10 00:04 发表 http://linux.chinaunix.net/bbs/images/common/back.gif



............................................................


:mrgreen: :mrgreen:别编辑你的回复呀!

着急了,是吧。继续~ 兄弟我看着你的戏   :mrgreen: :mrgreen:

cjaizss 发表于 2008-06-10 08:46

写的太不详细,你既然是在发帖子,就应该仔细说明gcc的处理方式,比如保留在什么地方,谁来清栈........

system888net 发表于 2008-06-11 11:27

原帖由 cjaizss 于 2008-6-10 08:46 发表 http://linux.chinaunix.net/bbs/images/common/back.gif
写的太不详细,你既然是在发帖子,就应该仔细说明gcc的处理方式,比如保留在什么地方,谁来清栈........

提醒的对.
已加了一些说明,不知道道能否说的清楚些.

[ 本帖最后由 system888net 于 2008-6-11 15:28 编辑 ]

system888net 发表于 2008-06-11 11:34

也就是说明: 在gcc里, 对于结构体的返回:return(psa); 这个动作实际上是在fun1内的对ll各成员赋值的一个,而fun1内对ll的识别是靠main调用fun1时传入的ll的地址来确定的.
页: [1] 2
查看完整版本: 结构体作为传递和返回值的小例子