0%

11-结构体

结构体

1
2
3
4
struct AA
{

}

返回结构体

1
2
3
4
lea eax,[ebp-30h]
push eax
call
# 这样利用地址存储返回的结构体

练习

  1. 定义一个结构体Gamer用来存储一个游戏中的角色的信息,包括血值、等级、坐标等信息
    • 具体包含哪些信息自由设计
    • 但这些包含的类型中,必须要有一个成员是结构体类型
  2. 定义一个函数,用来给这个结构体变量赋值
  3. 定义一个函数,用来显示这个结构体变量的所有成员信息

c语言都没经常写,复习下吧,练练手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
struct Point
{
float x;
float y;
float z;
};
struct Gamer
{
int blood;
int level;
Point point;
};

Gamer gamer;

void setGamer(int blood,int level,Point point)
{
gamer.blood = blood;
gamer.level = level;
gamer.point = point;
}

void showGamer()
{
printf("blood is:%d\n", gamer.blood);
printf("level is:%d\n", gamer.level);
printf("point is x:%f,y:%f,z:%f\n", gamer.point.x, gamer.point.y, gamer.point.z);
}
int main(int argc, char* argv[])
{
Point where;
where.x = 1;
where.y = 2;
where.z = 3;
setGamer(1,1,where);
showGamer();
return 0;
}

结构体对齐

1
2
3
#pragma pack(n)
//结构体 对齐参数:n为字节对齐数,其取值为1、2、4、8,默认是8。
#pragma pack

对齐原则:

  1. 数据成员对齐规则:结构的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储).
  2. 结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
  3. 该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储).(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储.)
  4. 对齐参数如果比结构体成员的sizeof值小,该成员的偏移量应该以此值为准.

练习

  1. 定义一个结构体Monster,能够存储怪的各种信息(至少有一个成员是结构体类型)。
  2. 声明一个Monster类型的数组,长度为10.
  3. 编写一个函数,为第二题中的数组赋值.
  4. 编写一个函数,能够通过怪物ID,打印当前这个怪物的所有信息.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
struct Point
{
float x;
float y;
float z;
};

struct Monster
{
int blood;
int level;
Point point;
};

Monster monster[10];

void setMonster()
{
for(int i=0; i<10; i++)
{
monster[i].blood = 100;
monster[i].level = 10;
monster[i].point.x = 2;
monster[i].point.y = 3;
monster[i].point.z = 4;
}
}

void showMonster(int id)
{
printf("blood: %d\n", monster[id].blood);
printf("level: %d\n", monster[id].level);
printf("x: %f\n", monster[id].point.x);
printf("y: %f\n", monster[id].point.y);
printf("z: %f\n", monster[id].point.z);
}
int main(int argc, char* argv[])
{
setMonster();
showMonster(2);
return 0;
}

分析下面结构体的内存分配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct S1
{
char c;
double i;
};
struct S2
{
char c1;
S1 s;
char c2;
char c3;
};
struct S3
{
char c1;
S1 s;
char c2;
double c3;
};
struct S4
{
int c1;
char c2[10];
}

S1结构体

结果是16,c按一字节对齐,是c,然后结构体内最大是double,8个字节,所以按8字节补全,合起来16个字节,也就是0x10字节

S2结构体

结果是16+2*8=32=0x20

首先char都是按1字节对齐了,然后S1分析过了,是16字节,整体按double补全,所以开头一个char 补全7个字节,后面两个char,补全6个字节,中间16个字节

S3结构体

结果是16+2*8+8=40=0x28

S1依旧16字节,char c1是1字节,按最大8字节补齐,c2旁边没有,也按8字节补齐,double接上

S4结构体

结果是4+8+4 = 16

char类型数组相当于叠了10个char,所以一个个叠下去最后剩下两个,两个按int补齐,所有就是16字节

总结

大胆猜想,小心论证,做完后实验,与理论相同

递归反汇编分析练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int fcb(int n)
{
if(n==0)
return 0;
else if(n==1)
return 1;
else
return fcb(n-1) +fcb(n-2);

}
int main(int argc, char* argv[])
{
int result = fcb(3);
printf("%d\n", result);
return 0;
}

大概函数逆向出来了,接着编写代码,运行一下就知道了?

我跟踪了下整个过程,fcb(3)

首先他会执行fcb(3-1)->fcb(2-1)->fcb(1)

然后从fcb(1)那一层返回去执行fcb(2-1)+fcb(2-2)

在返回一层执行fcb(3-1)+fcb(3-2)

所以整体就是 fcb(3-2) + fcb(3-1) = fcb(1) +(fcb(0) + fcb(1))

实际结果就是1+0+1=2

本文作者:NoOne
本文地址https://noonegroup.xyz/posts/f663c03f/
版权声明:转载请注明出处!