滴水逆向初级-C语言(二)
2.1.C语言的汇编表示
c语言代码
int plus(int x,int y)
{
return 0;
}
void main()
{
__asm
{
mov eax,eax
}
//调用函数
plus(1,2);
return;
}
汇编代码
1:
2: int plus(int x,int y)
3: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,40h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-40h]
0040102C mov ecx,10h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
4: return 0;
00401038 xor eax,eax
5: }
0040103A pop edi
0040103B pop esi
0040103C pop ebx
0040103D mov esp,ebp
0040103F pop ebp
00401040 ret
--- No source file -------------------------------------------------------------------------------------------------------------------------------------
00401041 int 3
00401042 int 3
00401043 int 3
00401044 int 3
0040104F int 3
--- C:\Program Files\Microsoft Visual Studio\MyProjects\11\test.cpp ------------------------------------------------------------------------------------
6:
7: void main()
8: {
00401050 push ebp
00401051 mov ebp,esp
00401053 sub esp,40h
00401056 push ebx
00401057 push esi
00401058 push edi
00401059 lea edi,[ebp-40h]
0040105C mov ecx,10h
00401061 mov eax,0CCCCCCCCh
00401066 rep stos dword ptr [edi]
9: plus(1,2); //调用函数
00401068 push 2
0040106A push 1
0040106C call @ILT+0(plus) (00401005)
00401071 add esp,8
10:
11: return;
12: }
00401074 pop edi
00401075 pop esi
00401076 pop ebx
00401077 add esp,40h
0040107A cmp ebp,esp
0040107C call __chkesp (004010a0)
00401081 mov esp,ebp
00401083 pop ebp
00401084 ret
--- No source file -------------------------------------------------------------------------------------------------------------------------------------
00401085 int 3
2.2.参数传递与返回值
1、函数定义
返回类型函数名(参数列表)
{
return
}
例子:
int plus(int x,int y)
{
return x+y;
}
2.画堆栈图
int plus(int x,int y)
{
return x+y;
}
void main()
{
__asm
{
mov eax,eax //断点调试 F7,F5,右键Go To Disassembly. F10单步,call按F11
}
plus(1,2);
return;
}
3.汇编代码
1:
2: int plus(int x,int y)
3: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,40h //提升堆栈
00401026 push ebx
00401027 push esi
00401028 push edi //保存要用到的寄存器的值
00401029 lea edi,[ebp-40h]
0040102C mov ecx,10h //ecx=10h,ecx是计数器
00401031 mov eax,0CCCCCCCCh //eax=CCCCCCCC
00401036 rep stos dword ptr [edi] //把eax的值写到[edi],写的次数:ecx的值
4: return x+y;
00401038 mov eax,dword ptr [ebp+8] //第一个参数的值,eax=1
0040103B add eax,dword ptr [ebp+0Ch] //第一个参数+第二个参数 eax=1+2
5: }
0040103E pop edi
0040103F pop esi
00401040 pop ebx
00401041 mov esp,ebp
00401043 pop ebp //还原堆栈
00401044 ret //eip=00401083, esp+4
--- No source file -------------------------------------------------------------------------------------------------------------------------------------
00401045 int 3
00401046 int 3
--- C:\Program Files\Microsoft Visual Studio\MyProjects\11\test.cpp ------------------------------------------------------------------------------------
6:
7: void main()
8: {
00401050 push ebp
00401051 mov ebp,esp
00401053 sub esp,40h
00401056 push ebx
00401057 push esi
00401058 push edi
00401059 lea edi,[ebp-40h]
0040105C mov ecx,10h
00401061 mov eax,0CCCCCCCCh
00401066 rep stos dword ptr [edi]
9: __asm
10: {
11: mov eax,eax
00401068 mov eax,eax
12: }
13:
14: plus(1,2);
0040106A push 2 //通过堆栈传参数
0040106C push 1
0040106E call @ILT+0(plus) (00401005)
00401073 add esp,8 //还原堆栈
15:
16: return;
17: }
00401076 pop edi
00401077 pop esi
00401078 pop ebx
00401079 add esp,40h
0040107C cmp ebp,esp
0040107E call __chkesp (004010a0)
00401083 mov esp,ebp
00401085 pop ebp
00401086 ret
--- No source file -------------------------------------------------------------------------------------------------------------------------------------
00401087 int 3
00401088 int 3
3、参数是如何传递的
C语言中参数传递:堆栈传参数从右到左
4、返回值存在哪里?返回值用了吗?
C语言中,返回值存储在EAX中
2.3.变量
1、声明变量
变量类型变量名;
变量类型用来说明宽度是多大
int 4个字节
short 2个字节
char 1个字节
变量名的命名规则:
1、只能以字母、数字、下划线组成,且第一个字母必须是字母或下划线
2、区分大小写
3、不能使用C语言的关键字
2、全局变量:
1)编译的时候就已经确定了内存地址和宽度,变量名就是内存地址的别名。
2)如果不重写编译,全局变量的内存地址不变。游戏外挂中的找“基址”,其实就
是找全局变量。|
3)全局变量中的值任何程序都可以改,是公用的。
例子: CE搜索基址
C语言代码
#include <windows.h>
#include <stdio.h>
int x;
void main()
{
x = 1234567;
while(1)
{
Sleep(3000);
printf("%d\n",x);
}
return;
}
3、局部变量
1)局部变量是函数内部申请的,如果函数没有执行,那么局部变量没有内存空间。
2)局部变量的内存是在堆栈中分配的,程序执行时才分配。我们无法预知程序何时
执行,这也就意味着,我们无法确定局部变量的内存地址。
3)因为局部变量地址内存是不确定的,所以,局部变量只能在函数内部使用,其他
函数不能使用。
2.4.变量与参数的内存布局
c语言代码
int plus(int x,int y)
{
int z = x + y;
return z;
}
void main()
{
int r;
r = plus(1,2);
return;
}
汇编代码
1:
2: int plus(int x,int y)
3: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,44h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
4: int z = x + y;
00401038 mov eax,dword ptr [ebp+8]
0040103B add eax,dword ptr [ebp+0Ch]
0040103E mov dword ptr [ebp-4],eax //[ebp-4]存放局部变量
5: return z;
00401041 mov eax,dword ptr [ebp-4]
6: }
00401044 pop edi
00401045 pop esi
00401046 pop ebx
00401047 mov esp,ebp
00401049 pop ebp
0040104A ret
--- No source file -----------------------------------------------------------------------------------------------
0040104B int 3
0040104C int 3
--- C:\Program Files\Microsoft Visual Studio\MyProjects\11\test.cpp ----------------------------------------------
7:
8: void main()
9: {
00401060 push ebp
00401061 mov ebp,esp
00401063 sub esp,44h
00401066 push ebx
00401067 push esi
00401068 push edi
00401069 lea edi,[ebp-44h]
0040106C mov ecx,11h
00401071 mov eax,0CCCCCCCCh
00401076 rep stos dword ptr [edi]
10: int r;
11: r = plus(1,2);
00401078 push 2
0040107A push 1
0040107C call @ILT+0(plus) (00401005)
00401081 add esp,8
00401084 mov dword ptr [ebp-4],eax
12: return;
13: }
00401087 pop edi
00401088 pop esi
00401089 pop ebx
0040108A add esp,44h
0040108D cmp ebp,esp
0040108F call __chkesp (004010b0)
00401094 mov esp,ebp
00401096 pop ebp
00401097 ret
--- No source file -----------------------------------------------------------------------------------------------
00401098 int 3
00401099 int 3
堆栈图
1.5.函数嵌套调用的内存布局
C语言代码
#include<stdio.h>
int plus1(int x,int y)
{
return x+y;
}
int plus(int x,int y,int z)
{
int m = plus1(x,y);
return m+z;
}
void main()
{
int r;
r = plus(1,2,3);
printf("%d",r);
return;
}
汇编代码
1: #include<stdio.h>
2:
3: int plus1(int x,int y)
4: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,40h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-40h]
0040102C mov ecx,10h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
5: return x+y;
00401038 mov eax,dword ptr [ebp+8]
0040103B add eax,dword ptr [ebp+0Ch]
6: }
0040103E pop edi
0040103F pop esi
00401040 pop ebx
00401041 mov esp,ebp
00401043 pop ebp
00401044 ret
--- No source file -----------------------------------------------------------------------------------------------
00401045 int 3
00401046 int 3
7:
8: int plus(int x,int y,int z)
9: {
00401060 push ebp
00401061 mov ebp,esp
00401063 sub esp,44h
00401066 push ebx
00401067 push esi
00401068 push edi
00401069 lea edi,[ebp-44h]
0040106C mov ecx,11h
00401071 mov eax,0CCCCCCCCh
00401076 rep stos dword ptr [edi]
10: int m = plus1(x,y);
00401078 mov eax,dword ptr [ebp+0Ch]
0040107B push eax
0040107C mov ecx,dword ptr [ebp+8]
0040107F push ecx
00401080 call @ILT+10(plus) (0040100f)
00401085 add esp,8
00401088 mov dword ptr [ebp-4],eax
11: return m+z;
0040108B mov eax,dword ptr [ebp-4]
0040108E add eax,dword ptr [ebp+10h]
12: }
00401091 pop edi
00401092 pop esi
00401093 pop ebx
00401094 add esp,44h
00401097 cmp ebp,esp
00401099 call __chkesp (004010b0)
0040109E mov esp,ebp
004010A0 pop ebp
004010A1 ret
--- No source file -----------------------------------------------------------------------------------------------
004010A2 int 3
004010A3 int 3
13:
14: void main()
15: {
0040B500 push ebp
0040B501 mov ebp,esp
0040B503 sub esp,44h
0040B506 push ebx
0040B507 push esi
0040B508 push edi
0040B509 lea edi,[ebp-44h]
0040B50C mov ecx,11h
0040B511 mov eax,0CCCCCCCCh
0040B516 rep stos dword ptr [edi]
16: int r;
17: r = plus(1,2,3);
0040B518 push 3
0040B51A push 2
0040B51C push 1 //传三个参数
0040B51E call @ILT+15(plus) (00401014)
0040B523 add esp,0Ch
0040B526 mov dword ptr [ebp-4],eax
18: printf("%d",r);
0040B529 mov eax,dword ptr [ebp-4]
0040B52C push eax
0040B52D push offset string "%d" (0041f10c)
0040B532 call printf (0040b770)
0040B537 add esp,8
19: return;
20: }
0040B53A pop edi
0040B53B pop esi
0040B53C pop ebx
0040B53D add esp,44h
0040B540 cmp ebp,esp
0040B542 call __chkesp (004010b0)
0040B547 mov esp,ebp
0040B549 pop ebp
0040B54A ret
--- No source file -----------------------------------------------------------------------------------------------
0040B54B int 3
0040B54C int 3
堆栈图
2.5.整数类型
1、整数类型的宽度:
char、short、 int、 long
char 8BIT 1字节 0~ 0xFF
short 16BIT 2字节 0~ 0xFFFF
int 32BIT 4字节 0 ~ 0xFFFFFFFF
long 32BIT 4字节 0 ~ 0xFFFFFFFF
特别说明:
int在16计算机中与short宽度-样,在32以上的计算机中与long同
2、存储格式:
charx=1; //0000 0001 0x01
charx= 1; //1111 1111 0xFF
5、有符号与无符号数(signed、 unsigned)
1)什么时候使用有符号、无符号
2)有符号与无符号的区别:
<1>正确理解有符号数与无符号数
<2>拓展时与比较时才有区别
2.6.if语句
C语言代码
#include<stdio.h>
#include<windows.h>
void main()
{
int x = 10;
int y = 20;
if(x>y)
{
printf("+++++\n");
}
else
{
printf("------\n");
}
return;
}
汇编代码
1: #include<stdio.h>
2: #include<windows.h>
3:
4: void main()
5: {
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,48h
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-48h]
0040101C mov ecx,12h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
6: int x = 10;
00401028 mov dword ptr [ebp-4],0Ah
7: int y = 20;
0040102F mov dword ptr [ebp-8],14h
8:
9: if(x>y)
00401036 mov eax,dword ptr [ebp-4]
00401039 cmp eax,dword ptr [ebp-8]
0040103C jle main+3Dh (0040104d)
10: {
11: printf("+++++\n");
0040103E push offset string "+++++\n" (00420028)
00401043 call printf (00401090)
00401048 add esp,4
12: }
13: else
0040104B jmp main+4Ah (0040105a)
14: {
15: printf("------\n");
0040104D push offset string "------\n" (0042001c)
00401052 call printf (00401090)
00401057 add esp,4
16: }
17:
18: return;
19: }
0040105A pop edi
0040105B pop esi
0040105C pop ebx
0040105D add esp,48h
00401060 cmp ebp,esp
00401062 call __chkesp (00401110)
00401067 mov esp,ebp
00401069 pop ebp
0040106A ret
--- No source file -----------------------------------------------------------------------------------------------
0040106B int 3
0040106C int 3
2.7.switch语句
当分支条件比较多得时候switch比if语句高效很多。
case条件按顺序时候的汇编代码
C语言代码
#include<stdio.h>
#include<windows.h>
void Myprint(int x)
{
switch(x)
{
case 1:
printf("A\n");
break;
case 2:
printf("B\n");
break;
case 3:
printf("C\n");
break;
case 4:
printf("D\n");
break;
case 5:
printf("E\n");
break;
}
}
void main()
{
Myprint(3);
return ;
}
汇编语言代码
1: #include<stdio.h>
2: #include<windows.h>
3:
4: void Myprint(int x)
5: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,44h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
6: switch(x)
7: {
00401038 mov eax,dword ptr [ebp+8]
0040103B mov dword ptr [ebp-4],eax
0040103E mov ecx,dword ptr [ebp-4]
00401041 sub ecx,1
00401044 mov dword ptr [ebp-4],ecx
00401047 cmp dword ptr [ebp-4],4
0040104B ja $L42195+0Dh (004010a0)
0040104D mov edx,dword ptr [ebp-4]
00401050 jmp dword ptr [edx*4+4010B1h]
8: case 1:
9: printf("A\n");
00401057 push offset string "A\n" (0042002c)
0040105C call printf (00401130)
00401061 add esp,4
10: break;
00401064 jmp $L42195+0Dh (004010a0)
11: case 2:
12: printf("B\n");
00401066 push offset string "B\n" (00420028)
0040106B call printf (00401130)
00401070 add esp,4
13: break;
00401073 jmp $L42195+0Dh (004010a0)
14: case 3:
15: printf("C\n");
00401075 push offset string "C\n" (00420024)
0040107A call printf (00401130)
0040107F add esp,4
16: break;
00401082 jmp $L42195+0Dh (004010a0)
17: case 4:
18: printf("D\n");
00401084 push offset string "D\n" (00420020)
00401089 call printf (00401130)
0040108E add esp,4
19: break;
00401091 jmp $L42195+0Dh (004010a0)
20: case 5:
21: printf("E\n");
00401093 push offset string "E\n" (0042001c)
00401098 call printf (00401130)
0040109D add esp,4
22: break;
23: }
24: }
004010A0 pop edi
004010A1 pop esi
004010A2 pop ebx
004010A3 add esp,44h
004010A6 cmp ebp,esp
004010A8 call __chkesp (004011b0)
004010AD mov esp,ebp
004010AF pop ebp
004010B0 ret
004010B1 push edi
004010B2 adc byte ptr [eax],al
004010B5 adc byte ptr [eax],al
004010B9 jne Myprint+0ABh (004010cb)
004010BB inc eax
004010BC add byte ptr [eax+edx+10930040h],al
004010C3 inc eax
004010C4 add ah,cl
--- No source file -----------------------------------------------------------------------------------------------
004010C6 int 3
004010C7 int 3
case条件不按顺序时候的汇编代码
c语言代码
#include<stdio.h>
#include<windows.h>
void Myprint(int x)
{
switch(x)
{
case 1:
printf("A\n");
break;
case 2:
printf("B\n");
break;
case 4:
printf("C\n");
break;
case 7:
printf("D\n");
break;
case 8:
printf("E\n");
break;
}
}
void main()
{
Myprint(3);
return ;
}
汇编代码
: #include<stdio.h>
2: #include<windows.h>
3:
4: void Myprint(int x)
5: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,44h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
6: switch(x)
7: {
00401038 mov eax,dword ptr [ebp+8]
0040103B mov dword ptr [ebp-4],eax
0040103E mov ecx,dword ptr [ebp-4]
00401041 sub ecx,1
00401044 mov dword ptr [ebp-4],ecx
00401047 cmp dword ptr [ebp-4],7
0040104B ja $L42196+0Dh (004010a0)
0040104D mov edx,dword ptr [ebp-4]
00401050 jmp dword ptr [edx*4+4010B1h]
8: case 1:
9: printf("A\n");
00401057 push offset string "A\n" (0042002c)
0040105C call printf (00401130)
00401061 add esp,4
10: break;
00401064 jmp $L42196+0Dh (004010a0)
11: case 2:
12: printf("B\n");
00401066 push offset string "B\n" (00420028)
0040106B call printf (00401130)
00401070 add esp,4
13: break;
00401073 jmp $L42196+0Dh (004010a0)
14: case 4:
15: printf("C\n");
00401075 push offset string "C\n" (00420024)
0040107A call printf (00401130)
0040107F add esp,4
16: break;
00401082 jmp $L42196+0Dh (004010a0)
17: case 7:
18: printf("D\n");
00401084 push offset string "D\n" (00420020)
00401089 call printf (00401130)
0040108E add esp,4
19: break;
00401091 jmp $L42196+0Dh (004010a0)
20: case 8:
21: printf("E\n");
00401093 push offset string "E\n" (0042001c)
00401098 call printf (00401130)
0040109D add esp,4
22: break;
23: }
24: }
004010A0 pop edi
004010A1 pop esi
004010A2 pop ebx
004010A3 add esp,44h
004010A6 cmp ebp,esp
004010A8 call __chkesp (004011b0)
004010AD mov esp,ebp
004010AF pop ebp
004010B0 ret
004010B1 push edi
004010B2 adc byte ptr [eax],al
004010B5 adc byte ptr [eax],al
004010B9 mov al,[75004010]
004010BE adc byte ptr [eax],al
004010C1 mov al,[A0004010]
004010C6 adc byte ptr [eax],al
004010C9 test byte ptr [eax],dl
004010CB inc eax
004010CC add byte ptr [ebx-33FFBFF0h],dl
--- No source file -----------------------------------------------------------------------------------------------
004010D2 int 3
004010D3 int 3
case条件中间不连续(3,5,6)的地方,会填充为default的地址,
2.8.for循环
C语言代码
#include<stdio.h>
#include<windows.h>
void Myprint()
{
int i;
for(i=0;i<10;i++)
{
printf("%d\n",i);
}
}
void main()
{
Myprint();
return ;
}
汇编代码
1: #include<stdio.h>
2: #include<windows.h>
3:
4: void Myprint()
5: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,44h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
6: int i;
7: for(i=0;i<10;i++)
00401038 mov dword ptr [ebp-4],0
0040103F jmp Myprint+2Ah (0040104a)
00401041 mov eax,dword ptr [ebp-4]
00401044 add eax,1
00401047 mov dword ptr [ebp-4],eax
0040104A cmp dword ptr [ebp-4],0Ah
0040104E jge Myprint+43h (00401063)
8: {
9: printf("%d\n",i);
00401050 mov ecx,dword ptr [ebp-4]
00401053 push ecx
00401054 push offset string "E\n" (0042001c)
00401059 call printf (00401130)
0040105E add esp,8
10: }
00401061 jmp Myprint+21h (00401041)
11: }
00401063 pop edi
00401064 pop esi
00401065 pop ebx
00401066 add esp,44h
00401069 cmp ebp,esp
0040106B call __chkesp (004011b0)
00401070 mov esp,ebp
00401072 pop ebp
00401073 ret
--- No source file ---------------------------------------------------------------------------------------------------------------------
00401074 int 3
00401075 int 3
2.9.数组
C语言代码
#include<stdio.h>
#include<windows.h>
void main()
{
int age[5]={1,2,3,4,5};
int x,y;
x = age[0];
age[1]=6;
y = age[1];
printf("%d\n%d",x,y);
return ;
}
汇编代码
1: #include<stdio.h>
2: #include<windows.h>
3:
4:
5: void main()
6: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,5Ch
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-5Ch]
0040102C mov ecx,17h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
7: int age[5]={1,2,3,4,5};
00401038 mov dword ptr [ebp-14h],1
0040103F mov dword ptr [ebp-10h],2
00401046 mov dword ptr [ebp-0Ch],3
0040104D mov dword ptr [ebp-8],4
00401054 mov dword ptr [ebp-4],5
8: int x,y;
9: x = age[0];
0040105B mov eax,dword ptr [ebp-14h]
0040105E mov dword ptr [ebp-18h],eax
10: age[1]=6;
00401061 mov dword ptr [ebp-10h],6
11: y = age[1];
00401068 mov ecx,dword ptr [ebp-10h]
0040106B mov dword ptr [ebp-1Ch],ecx
12: printf("%d\n%d",x,y);
0040106E mov edx,dword ptr [ebp-1Ch]
00401071 push edx
00401072 mov eax,dword ptr [ebp-18h]
00401075 push eax
00401076 push offset string "%d\n%d" (0042001c)
0040107B call printf (00401130)
00401080 add esp,0Ch
13: return ;
14: }
00401083 pop edi
00401084 pop esi
00401085 pop ebx
00401086 add esp,5Ch
00401089 cmp ebp,esp
0040108B call __chkesp (004011b0)
00401090 mov esp,ebp
00401092 pop ebp
00401093 ret
--- No source file ---------------------------------------------------------------------------------------------------------------------
00401094 int 3
00401095 int 3
2.10.多维数组
C语言代码
#include<stdio.h>
#include<windows.h>
void main()
{
int arr[3][4] =
{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
return ;
}
汇编代码
1: #include<stdio.h>
2: #include<windows.h>
3:
4:
5: void main()
6: {
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,70h
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-70h]
0040101C mov ecx,1Ch
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
7: int arr[3][4] =
8: {
9: {1,2,3,4},
00401028 mov dword ptr [ebp-30h],1
0040102F mov dword ptr [ebp-2Ch],2
00401036 mov dword ptr [ebp-28h],3
0040103D mov dword ptr [ebp-24h],4
10: {5,6,7,8},
00401044 mov dword ptr [ebp-20h],5
0040104B mov dword ptr [ebp-1Ch],6
00401052 mov dword ptr [ebp-18h],7
00401059 mov dword ptr [ebp-14h],8
11: {9,10,11,12}
00401060 mov dword ptr [ebp-10h],9
00401067 mov dword ptr [ebp-0Ch],0Ah
0040106E mov dword ptr [ebp-8],0Bh
00401075 mov dword ptr [ebp-4],0Ch
12: };
13:
14: return ;
15: }
0040107C pop edi
0040107D pop esi
0040107E pop ebx
0040107F mov esp,ebp
00401081 pop ebp
00401082 ret
--- No source file ---------------------------------------------------------------------------------------------------------------------
00401083 int 3
00401084 int 3
2.11.结构体
结构体类型的定义:
struct类型名{
//可以定义多种类型
inta;
char b;
short c;
};
<1> char/int/数组等是编译器已经认识的类型:内置类型
<2>结构体是编译器不认识的,用的时候需要告诉编译器-声:自定义类型
<3>.上面的代码仅仅是告诉编译器我们自己定义的类型是什么样的,本身并不占用内存。
定义结构体类型的时候,直接定义变量
struct stPoint{
int x;
int y;
}point1 ,point2,point3;
//这种方式是分配内存的,因为不仅仅是定义新的类型,还定义了3个全局变量
2.12.字节对齐
1.什么是字节对齐呢?
char X;
short y;|
intz;
字节对齐:
一个变量占用n个字节,则该变量的起始地址必须是n的整数倍,即:存放起始地址% n=0。
如果是结构体,那么结构体的起始地址是其最宽数据类型成员的整数倍。
2.结构体字节对齐占用空间大小
#include<stdio.h>
#include<windows.h>
struct test1{
char a;
int b;
};
struct test2{
char c;
double d;
};
int check()
{
printf("%d\n",sizeof(test1)); //8
printf("%d\n",sizeof(test2)); //16
return 0;
}
void main()
{
check();
getchar();
return ;
}
3.当对空间要求较高的时候,可以通过#pragma pack(n)来改变结构体成员的对齐方式
#pragma pack(1)
structTest{
char a;
int b;
};
#pragma pack()
<1> #pragma pack(n)中n用来设定变量以n字节对齐方式,可以设定的值包括: 1、2、4、8,VC编译器默认是8。
<2>若需取消强制对齐方式,则可用命令#pragma pack()
<3>结构体大总大小: N = Min(最大成员,对齐参数)是N的整数倍
2.13.指针类型
1、定义带“*”类型的变量
1、带有**的变量类型的标准写法:变量类型* * 变量名。
2、任何类型都可以带* 加上* 以后是新的类型,统称“指针类型”。
3、*可以是任意多个。
2、指针宽度
指针类型的变量宽度永远是4字节、无论类型是什么,无论有几个*。
char* a
short* b
int* c
3、指针类型的自加和自减
1、不带类型的变量,++或者-都是加1或者减1
2、带类型的变量,++或者-新增(减少)的数量是去掉-一个*后变量的宽度
#include<stdio.h>
#include<windows.h>
void main()
{
char* a;
short* b;
int* c;
a = (char*)100;
b = (short*)100;
c = (int*)100;
a++; //减掉一个*后就是char的宽度,1
b++; //减掉一个*后就是short的宽度,2
c++; //减掉一个*后就是int的宽度,4
printf("%d %d %d\n",a,b,c); //101 102 104
system("pause");
return ;
}
#include<stdio.h>
#include<windows.h>
void main()
{
char** a;
short** b;
int** c;
a = (char**)100;
b = (short**)100;
c = (int**)100;
a++; //减掉一个*后就是char*的宽度,4
b++; //减掉一个*后就是short*的宽度,4
c++; //减掉一个*后就是int*的宽度,4
printf("%d %d %d\n",a,b,c); //104 104 104
system("pause");
return ;
}
4、指针类型的加减运算
1、指针类型的变量可以加、减-一个整数,但不能乘或者除.
2、指针类型变量与其他整数相加或者相减时:
指针类型变量+N = 指针类型变量+ N * (去掉-一个* 后类型的宽度)
指针类型变量-N = 指针类型变量- N * (去掉-一个 * 后类型的宽度)
#include<stdio.h>
#include<windows.h>
void main()
{
char* a;
short* b;
int* c;
a = (char*)100;
b = (short*)100;
c = (int*)100;
a = a + 5; // a = 100+(1x5)
b = b + 5; // b = 100+(2x5)
c = c + 5; // c = 100+(4x5)
printf("%d %d %d\n",a,b,c); //105 110 120
system("pause");
return ;
}
#include<stdio.h>
#include<windows.h>
void main()
{
char** a;
short** b;
int** c;
a = (char**)100;
b = (short**)100;
c = (int**)100;
a = a + 5; // a = 100+(4x5)
b = b + 5; // b = 100+(4x5)
c = c + 5; // c = 100+(4x5)
printf("%d %d %d\n",a,b,c); //120 120 120
system("pause");
return ;
}
5、指针类型可以做大小比较
#include<stdio.h>
#include<windows.h>
void main()
{
char* a;
char* b;
a = (char*)200;
b = (char*)100;
if(a>b)
{
printf("1\n"); //1
}
else
{
printf("2\n");
}
system("pause");
return ;
}
2.14.&的使用
&是取地址符,任何变量都可以使用&来获取地址,但不能用在常量上。
指针变量赋值
#include<stdio.h>
#include<windows.h>
void main()
{
char x;
char* p1;
char** p2;
char*** p3;
char**** p4;
p1 = &x; //char*
p2 = &p1; //char**
p3 = &p2; //cahr***
p4 = &p3; //char****
system("pause");
return ;
}
2.15.取值运算符
1、 * 指针类型 的类型
*加指针类型 的类型是 指针类型减去一个 *
#include<stdio.h>
#include<windows.h>
void main()
{
int*** a;
int** b;
int* c;
int x = *(a); //a是int***类型,*(a)是int**类型
int y = *(b); //b是int**类型,*(b)是int*类型
int z = *(c); //c是int*类型,*(c)是int类型
system("pause");
return ;
}
取值运算符举例
C语言代码
#include<stdio.h>
#include<windows.h>
int x = 1;
int* p1;
int** p2;
int*** p3;
void main()
{
p1 = &x;
p2 = &p1;
p3=&p2;
int r = *(*(*(p3)));
printf("%d\n",r);
system("pause");
return ;
}
汇编代码
1: #include<stdio.h>
2: #include<windows.h>
3:
4: int x = 1;
5: int* p1;
6: int** p2;
7: int*** p3;
8:
9: void main()
10: {
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,44h
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-44h]
0040101C mov ecx,11h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
11: p1 = &x;
00401028 mov dword ptr [p1 (004255ec)],offset x (00424a30)
12: p2 = &p1;
00401032 mov dword ptr [p2 (004255f0)],offset p1 (004255ec)
13: p3=&p2;
0040103C mov dword ptr [p3 (004255f4)],offset p2 (004255f0)
14:
15: int r = *(*(*(p3)));
00401046 mov eax,[p3 (004255f4)]
0040104B mov ecx,dword ptr [eax]
0040104D mov edx,dword ptr [ecx]
0040104F mov eax,dword ptr [edx]
00401051 mov dword ptr [ebp-4],eax
16: printf("%d\n",r);
00401054 mov ecx,dword ptr [ebp-4]
00401057 push ecx
00401058 push offset string "%d\n" (00422024)
0040105D call printf (004011b0)
00401062 add esp,8
17:
18: system("pause");
00401065 push offset string "pause" (0042201c)
0040106A call system (004010a0)
0040106F add esp,4
19: return ;
20: }
00401072 pop edi
00401073 pop esi
00401074 pop ebx
00401075 add esp,44h
00401078 cmp ebp,esp
0040107A call __chkesp (00401230)
0040107F mov esp,ebp
00401081 pop ebp
00401082 ret
--- No source file --------------------------------------------------------------------------------------------------------------------------------
00401083 int 3
2.16.数组参数传递
1、数组作为参数:****
1.传递的是数组的首地址(也就是数组 第一个元素的地址)
2.应该传递数组的长度
C语言代码
#include<stdio.h>
#include<windows.h>
void PrintArray(int arr[], int nLength)
{
for(int i=0;i<nLength;i++)
{
printf("%d\n",arr[i]);
}
}
void main()
{
int arr[5] = {1,2,3,4,5};
PrintArray(arr,5);
system("pause");
return ;
}
汇编代码
1: #include<stdio.h>
2: #include<windows.h>
3:
4: void PrintArray(int arr[], int nLength)
5: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,44h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
6: for(int i=0;i<nLength;i++)
00401038 mov dword ptr [ebp-4],0
0040103F jmp PrintArray+2Ah (0040104a)
00401041 mov eax,dword ptr [ebp-4]
00401044 add eax,1
00401047 mov dword ptr [ebp-4],eax
0040104A mov ecx,dword ptr [ebp-4]
0040104D cmp ecx,dword ptr [ebp+0Ch]
00401050 jge PrintArray+4Bh (0040106b)
7: {
8: printf("%d\n",arr[i]);
00401052 mov edx,dword ptr [ebp-4]
00401055 mov eax,dword ptr [ebp+8]
00401058 mov ecx,dword ptr [eax+edx*4]
0040105B push ecx
0040105C push offset string "%d\n" (0042201c)
00401061 call printf (00401120)
00401066 add esp,8
9: }
00401069 jmp PrintArray+21h (00401041)
10: }
0040106B pop edi
0040106C pop esi
0040106D pop ebx
0040106E add esp,44h
00401071 cmp ebp,esp
00401073 call __chkesp (004011a0)
00401078 mov esp,ebp
0040107A pop ebp
0040107B ret
--- No source file --------------------------------------------------------------------------------------------------------------------------------
0040107C int 3
--- c:\program files\microsoft visual studio\myprojects\11\test.cpp -------------------------------------------------------------------------------
11:
12: void main()
13: {
004010A0 push ebp
004010A1 mov ebp,esp
004010A3 sub esp,54h
004010A6 push ebx
004010A7 push esi
004010A8 push edi
004010A9 lea edi,[ebp-54h]
004010AC mov ecx,15h
004010B1 mov eax,0CCCCCCCCh
004010B6 rep stos dword ptr [edi]
14: int arr[5] = {1,2,3,4,5};
004010B8 mov dword ptr [ebp-14h],1
004010BF mov dword ptr [ebp-10h],2
004010C6 mov dword ptr [ebp-0Ch],3
004010CD mov dword ptr [ebp-8],4
004010D4 mov dword ptr [ebp-4],5
15: PrintArray(arr,5);
004010DB push 5
004010DD lea eax,[ebp-14h]
004010E0 push eax
004010E1 call @ILT+0(PrintArray) (00401005)
004010E6 add esp,8
16:
17: system("pause");
004010E9 push offset string "pause" (00422020)
004010EE call system (004011e0)
004010F3 add esp,4
18: return ;
19: }
004010F6 pop edi
004010F7 pop esi
004010F8 pop ebx
004010F9 add esp,54h
004010FC cmp ebp,esp
004010FE call __chkesp (004011a0)
00401103 mov esp,ebp
00401105 pop ebp
00401106 ret
--- No source file --------------------------------------------------------------------------------------------------------------------------------
00401107 int 3
2、用指针来操作数组
数组作为参数时,传递的人是地址
C语言代码
#include<stdio.h>
#include<windows.h>
void PrintArray(int* p, int nLength)
{
for(int i=0;i<nLength;i++)
{
printf("%d\n",*(p+i));
}
}
void main()
{
int arr[5] = {1,2,3,4,5};
PrintArray(&arr[0],5);
system("pause");
return ;
}
汇编代码
1: #include<stdio.h>
2: #include<windows.h>
3:
4: void PrintArray(int* p, int nLength)
5: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,44h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
6: for(int i=0;i<nLength;i++)
00401038 mov dword ptr [ebp-4],0
0040103F jmp PrintArray+2Ah (0040104a)
00401041 mov eax,dword ptr [ebp-4]
00401044 add eax,1
00401047 mov dword ptr [ebp-4],eax
0040104A mov ecx,dword ptr [ebp-4]
0040104D cmp ecx,dword ptr [ebp+0Ch]
00401050 jge PrintArray+4Bh (0040106b)
7: {
8: printf("%d\n",*(p+i));
00401052 mov edx,dword ptr [ebp-4]
00401055 mov eax,dword ptr [ebp+8]
00401058 mov ecx,dword ptr [eax+edx*4]
0040105B push ecx
0040105C push offset string "%d\n" (0042201c)
00401061 call printf (00401120)
00401066 add esp,8
9: }
00401069 jmp PrintArray+21h (00401041)
10: }
0040106B pop edi
0040106C pop esi
0040106D pop ebx
0040106E add esp,44h
00401071 cmp ebp,esp
00401073 call __chkesp (004011a0)
00401078 mov esp,ebp
0040107A pop ebp
0040107B ret
--- No source file --------------------------------------------------------------------------------------------------------------------------------
0040107C int 3
--- C:\Program Files\Microsoft Visual Studio\MyProjects\11\test.cpp -------------------------------------------------------------------------------
11:
12: void main()
13: {
004010A0 push ebp
004010A1 mov ebp,esp
004010A3 sub esp,54h
004010A6 push ebx
004010A7 push esi
004010A8 push edi
004010A9 lea edi,[ebp-54h]
004010AC mov ecx,15h
004010B1 mov eax,0CCCCCCCCh
004010B6 rep stos dword ptr [edi]
14: int arr[5] = {1,2,3,4,5};
004010B8 mov dword ptr [ebp-14h],1
004010BF mov dword ptr [ebp-10h],2
004010C6 mov dword ptr [ebp-0Ch],3
004010CD mov dword ptr [ebp-8],4
004010D4 mov dword ptr [ebp-4],5
15: PrintArray(&arr[0],5);
004010DB push 5
004010DD lea eax,[ebp-14h]
004010E0 push eax
004010E1 call @ILT+10(PrintArray) (0040100f)
004010E6 add esp,8
16:
17: system("pause");
004010E9 push offset string "pause" (00422020)
004010EE call system (004011e0)
004010F3 add esp,4
18: return ;
19: }
004010F6 pop edi
004010F7 pop esi
004010F8 pop ebx
004010F9 add esp,54h
004010FC cmp ebp,esp
004010FE call __chkesp (004011a0)
00401103 mov esp,ebp
00401105 pop ebp
00401106 ret
--- No source file --------------------------------------------------------------------------------------------------------------------------------
00401107 int 3
2.17.指针与字符串
1、字符串的几种表示方式有什么区别?
char str[6] = {'A','B','C','D',E','0'}; //结尾要 '\O'或者0
char str[] = "ABCDE", //编译器末尾填0
char* str= "ABCDE"; //常量区
//打印
print("%s\n" ,str);
2、常用的字符串函数
1、int strlen (char* s)
返回值是字符串s的长度。不包括结束符'/0'。
2、char* strcpy (char* dest, char* src);
复制字符串src到dest中。返回指针为dest的值。
3、char* strcat (char* dest, char* src);
将字符串src添加到dest尾部。返回指针为dest的值。
4、int strcmp ( char* s1, char* s2);
一样返回0 不一样返回非0
2.18.指针取值的两种方式
1、一级指针和多级指针
c语言代码
#include<stdio.h>
#include<windows.h>
void main()
{
int i = 100;
int* p1 = &i;
int** p2 = &p1;
int*** p3 = &p2;
int**** p4 = &p3;
int***** p5 = &p4;
int****** p6 = &p5;
int******* p7 = &p6;
int y = *******p7; //y=1
int z= p7[0][0][0][0][0][0][0]; //z=1
system("pause");
return ;
}
汇编代码
1: #include<stdio.h>
2: #include<windows.h>
3:
4: void main()
5: {
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,68h
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-68h]
0040101C mov ecx,1Ah
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
6: int i = 100;
00401028 mov dword ptr [ebp-4],64h
7:
8: int* p1 = &i;
0040102F lea eax,[ebp-4]
00401032 mov dword ptr [ebp-8],eax
9: int** p2 = &p1;
00401035 lea ecx,[ebp-8]
00401038 mov dword ptr [ebp-0Ch],ecx
10: int*** p3 = &p2;
0040103B lea edx,[ebp-0Ch]
0040103E mov dword ptr [ebp-10h],edx
11: int**** p4 = &p3;
00401041 lea eax,[ebp-10h]
00401044 mov dword ptr [ebp-14h],eax
12: int***** p5 = &p4;
00401047 lea ecx,[ebp-14h]
0040104A mov dword ptr [ebp-18h],ecx
13: int****** p6 = &p5;
0040104D lea edx,[ebp-18h]
00401050 mov dword ptr [ebp-1Ch],edx
14: int******* p7 = &p6;
00401053 lea eax,[ebp-1Ch]
00401056 mov dword ptr [ebp-20h],eax
15:
16: int y = *******p7; //y=1
00401059 mov ecx,dword ptr [ebp-20h]
0040105C mov edx,dword ptr [ecx]
0040105E mov eax,dword ptr [edx]
00401060 mov ecx,dword ptr [eax]
00401062 mov edx,dword ptr [ecx]
00401064 mov eax,dword ptr [edx]
00401066 mov ecx,dword ptr [eax]
00401068 mov edx,dword ptr [ecx]
0040106A mov dword ptr [ebp-24h],edx
17:
18: int z= p7[0][0][0][0][0][0][0]; //z=1
0040106D mov eax,dword ptr [ebp-20h]
00401070 mov ecx,dword ptr [eax]
00401072 mov edx,dword ptr [ecx]
00401074 mov eax,dword ptr [edx]
00401076 mov ecx,dword ptr [eax]
00401078 mov edx,dword ptr [ecx]
0040107A mov eax,dword ptr [edx]
0040107C mov ecx,dword ptr [eax]
0040107E mov dword ptr [ebp-28h],ecx
19:
20:
21: system("pause");
00401081 push offset string "pause" (0042201c)
00401086 call system (004010d0)
0040108B add esp,4
22: return ;
23: }
0040108E pop edi
0040108F pop esi
00401090 pop ebx
00401091 add esp,68h
00401094 cmp ebp,esp
00401096 call __chkesp (004011e0)
0040109B mov esp,ebp
0040109D pop ebp
0040109E ret
--- No source file --------------------------------------------------------------------------------------------------------------------------------
0040109F int 3
2、总结:
*(p+i)= p[i]
*(*(p+i)+k) = p[i][k]
*(*(*(p+i)+k)+m) = p[i][k][m]
(*(p+i)+k)+m)+W)+t) = p[jIk]Im][W[t]
*()与[]可以相互转换
2.19.结构体指针
通过结构体指针读取和修改值
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
Point{
int x;
int y;
}
void main()
{
Point p = {1,2};
Point* px = &p;
int x = px->x; //x=1
px->y =100;
int u = px->y; //y=100
system("pause");
return ;
}
2.20.指针数组和数组指针
1、指针数组的定义
char arr[10]; //10 char
char* arr[10]; //10 指针(char*) 每个成员4字节
Point* arr[10]; //10 指针(Point*) 每个成员4字节
int******* arr[10]; // //10 指针(int*******) 每个成员4字节
2、指针数组的赋值
char* a = "hello"; //a存的是地址,里面存放的值是 “hello”
char* b = "你好";
//汇编代码
7: char* a = "hello";
00401028 mov dword ptr [ebp-4],offset string "hello" (004230cc)
8: char* b = "你好";
0040102F mov dword ptr [ebp-8],offset string "\xc4\xe3\xba\xc3" (004230c4)
char* arr1[2] = {a,b}; //存放两个地址a和b
char* arr2[2] = {"hello","你好"}; //存放的也是两个地址
//汇编代码
7: char* a = "hello";
00401028 mov dword ptr [ebp-4],offset string "hello" (0042202c)
8: char* b = "你好";
0040102F mov dword ptr [ebp-8],offset string "\xc4\xe3\xba\xc3" (00422024)
9:
10: char* arr1[2] = {a,b};
00401036 mov eax,dword ptr [ebp-4]
00401039 mov dword ptr [ebp-10h],eax
0040103C mov ecx,dword ptr [ebp-8]
0040103F mov dword ptr [ebp-0Ch],ecx
11: char* arr2[2] = {"hello","你好"};
00401042 mov dword ptr [ebp-18h],offset string "hello" (0042202c)
00401049 mov dword ptr [ebp-14h],offset string "\xc4\xe3\xba\xc3" (00422024)
3、结构体指针数组
struct Point
{
int x;
int y;
};
Point p; //8字节
Point arr[10]; //8x10字节
Point* arrPoint[10; //4x10字节
4、数组指针的定义
int(*px)[5];
char(*px)[5]; //一维数组指针
int(*px)[5][4]; //二维数组指针
5、数组指针的宽度与赋值
int(*px1) [5]; //一维数组指针
char(*px2) [3];
int(*px3) [2][2]; //二维数组指针
char(*px4) [3][3][3); //三维数组指针
print("%d %d %d %d \n" ,sizeof(px1),sizeof(px2),sizeof(px3),sizeof(px4)); //4 4 4 4
px1 = (int (*)[5])1;
px2 = (char (*)[(3])2;
px3 = (int (*)[2][2])3;
px4 = (char (*)[3][3][3])4;
6、数组指针的使用
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
void main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,0};
int(*px)[10] = &arr;
printf("%d\n",(*px)[0]); // 1
system("pause");
return ;
}
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
void main()
{
int arr[3][3] =
{
{1,2,3},
{4,5,6},
{7,8,9}
};
int(*px)[3] = &arr[0];
printf("%d %d\n",(*px)[0],(*px)[2]); //1 3
px++;
printf("%d %d\n",(*px)[0],(*px)[2]); //4 6
system("pause");
return ;
}
2.21.常见的几种调用约定:
三种常见调用约定
调用约定 参数压栈顺序 平衡堆栈
cdecl 从右至左入栈 调用者清理栈
stdcall 从右至左入栈 自身清理堆栈
_ _fastcall ECX/EDX传送前两个 自身清理堆栈
剩下:从右至左入栈
2.22.函数指针
1、函数指针类型变量的定义
函数指针变量定义的格式:
返回类型(调用约定 *变量名)(参数列表);
如:
int ( _cdecl *pFun)(int,int);
2、通过函数指针绕过断点
<1>函数指针变量的定义
int (__stdcall *pFun)(int,int,int,int,int);
<2>正常调用
MessaleBox(0,0,0,0);
<3>通过函数指针绕过断点
pFun = (int (__stdcall *)(int,int,int,int,int))0x77D5055C;
pFun(0,0,0,0,0);
2.23.预处理之宏定义
1、什么是预处理:
预处理一般是指在程序源代码被转换为二进制代码之前,由预处理器对程序源代码文本进行处理处理后的结再由编译器进- -步编译。
预处理功能主要包括宏定义,文件包含,条件编译三部分
2、宏定义
<1>简单宏: #define 标识符字符序列
# define FALSE 0
# define NAME "测试"
# define_ IN
# define__ OUT
<2>带参数的宏: #define 标识符(参数表)字符序列
#define MAX(A,B) ((A)> (B)?(A):(B))
注意事项:
1、只作字符序列的替换工作,不作任何语法的检查,在编译前处理。
2、宏名标识符与左圆括号之间不允许有空白符,应紧接在- -起。
3、为了避免出错,宏定义中给形参加上括号。
4、多行声明时,回车换行前要加上字符‘\’,即“[enter]" ,注意字符
‘\’ 后要紧跟回车键,中间不能有空格或其他字符。
5、末尾不需要分号。
2.24.条件编译与文件包含
1、什么是条件编译?
#if 0
printf("------")
#endif
2、预处理指令:条件编译是通过预处理指令实现的
3、文件包含有两种格式
分别是: #include "file"和#include
1.使用双引号,系统首先到当前目录下查找被包含的文件,如果没找到,再到系
统指定的"包含文件目录" (由用户在配置环境时设置)去找。
2.使用尖括号:直接到系统指定的"包含文件目录"去查找。
总结:
系统文件用<>
自己定义的文件用””
4、如何解决重复包含问题
- 条件编译
- 前置声明