结构体
返回结构体
1 2 3 4
| lea eax,[ebp-30h] push eax call # 这样利用地址存储返回的结构体
|
练习
- 定义一个结构体Gamer用来存储一个游戏中的角色的信息,包括血值、等级、坐标等信息
- 具体包含哪些信息自由设计
- 但这些包含的类型中,必须要有一个成员是结构体类型
- 定义一个函数,用来给这个结构体变量赋值
- 定义一个函数,用来显示这个结构体变量的所有成员信息
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)
#pragma pack
|
对齐原则:
- 数据成员对齐规则:结构的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储).
- 结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
- 该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储).(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储.)
- 对齐参数如果比结构体成员的sizeof值小,该成员的偏移量应该以此值为准.
练习
- 定义一个结构体Monster,能够存储怪的各种信息(至少有一个成员是结构体类型)。
- 声明一个Monster类型的数组,长度为10.
- 编写一个函数,为第二题中的数组赋值.
- 编写一个函数,能够通过怪物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/
版权声明:转载请注明出处!