结构体成员的访问:
struct rec {
inti;
int j;
int a[3];
int *p;
};
void copy(struct rec *r)
{
r->j = r->i;
}
gcc -O1 -S -m32 struct1.c
copy:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx //结构体r的指针
movl (%edx), %eax //eax =r->i
movl %eax, 4(%edx) //r->j =r->i
popl %ebp
ret
结构体之间的拷贝:
struct rec {
int i;
int j;
int a[3];
int *p;
};
void copy(struct rec *sr, struct rec *dr)
{
*dr= *sr;
}
gcc -O1 -S -m32 struct2.c
copy:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx //edx = sr
movl 12(%ebp), %ecx //ecx = dr
movl (%edx), %eax //eax =sr->i
movl %eax, (%ecx) //dr->I =sr->i
movl 4(%edx), %eax // eax =sr->j
movl %eax, 4(%ecx) //dr->j =sr->j
movl 8(%edx), %eax //eax =sr->a[0]
movl %eax, 8(%ecx)//dr->a[0] = sr->a[0]
movl 12(%edx), %eax //eax =sr->a[1]
movl %eax, 12(%ecx)//dr->a[1] = sr->a[1]
movl 16(%edx), %eax //eax =sr->a[2]
movl %eax, 16(%ecx)//dr->a[2] = sr->a[2]
movl 20(%edx), %eax //eax =sr->p
movl %eax, 20(%ecx) //dr->p= sr->p
popl %ebp
ret
把int a[3]改成int a[3000],再生成一次汇编代码:
copy:
pushl %ebp
movl %esp, %ebp
subl $24, %esp //esp=esp -24
movl $12012, 8(%esp) //esp+8 =12012,结构体的大小
movl 8(%ebp), %eax //eax = sr
movl %eax, 4(%esp) //esp+4 = sr
movl 12(%ebp), %eax //eax = dr
movl %eax, (%esp) //esp = dr
call memcpy //调用函数memcpy
leave //清理栈
ret
从本例可以看出,如果结构体比较小,结构体间的拷贝就是对构体的每个成员进行赋值。如果结构体很大,需要通过memcpy函数调用来完成拷贝动作。
值传递:
struct rec {
int i;
int j;
int a[3000];
int*p;
};
struct rec copy(struct rec *sr, struct rec*dr)
{
*dr = *sr;
return *dr;
}
gcc -O1 -S -m32 struct3.c
copy:
pushl %ebp
movl %esp, %ebp
subl $24, %esp //esp = esp -24
movl %ebx, -8(%ebp) // ebp -8 =ebx,备份ebx
movl %esi, -4(%ebp) //ebp -4=esi,备份esi
movl 8(%ebp), %esi //用于返回的结构体临时变量的地址
movl 16(%ebp), %ebx //ebx = dr
movl $12012, 8(%esp) //结构体大小装入esp +8
movl 12(%ebp), %eax //eax = sr
movl %eax, 4(%esp) //sr装入esp+4
movl %ebx, (%esp) //dr装入esp
call memcpy //调用memcpy
movl $12012, 8(%esp) //结构体大小装入esp +8
movl %ebx, 4(%esp) //dr装入esp+4,作为源
movl %esi, (%esp) //用于返回的结构体临时变量的地址装入esp,作为目的
call memmove //调用memmove
movl %esi, %eax //用于返回的结构体临时变量的地址装入eax作为返回值
movl -8(%ebp), %ebx //恢复ebx
movl -4(%ebp), %esi //恢复esi
movl %ebp, %esp
popl %ebp
ret $4 //表示在返回时,除了弹出返回地址外,还要把栈指针上移4个字节,因为在函数调用时调用者多加了一个临时变量的地址作为参数。
结构体临时变量应该放在栈中,这样当调用者保存返回值时,还会把结构体临时变量再拷贝一次,等于多做了两次拷贝操作,所以如果把结构体变量作为返回值,效率会很低。
结构体的嵌套:
struct prob {
int *p;
struct {
int x;
int y;
}s;
struct prob *next;
};
void sp_init(struct prob *sp)
{
sp->s.x = sp->s.y;
sp->p = &(sp->s.x);
sp->next = sp;
}
gcc -O1 -S -m32 struct4.c
sp_init:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax //eax = sp
movl 8(%eax), %edx // edx = sp->s.y
movl %edx, 4(%eax) //sp->s.x= sp->s.y
leal 4(%eax), %edx // edx =&(sp->s.x)
movl %edx, (%eax) // sp->p =&(sp->s.x)
movl %eax, 12(%eax) // sp->next= sp
popl %ebp
ret