转自:http://blog.youkuaiyun.com/feixiaoxing/article/details/6751534
很多朋友,包括我自己在内,对C++语言的很多特性不是很明白。特别是几年前找工作的时候,为了应付来自工作单位的考试,我经常逼着自己的去记住一些复杂的试题和答案。可是常常时间已过,一切又回到了原点。原来没有弄清楚的问题还是没有弄明白,一切都没有发生改变。直到若干年后,当我在编码过程中不断积累经验,尝试用汇编代码和内存数据来解释一些现象的时候,才明白有些东西其实并不复杂。也许有的朋友对汇编语言会有畏惧,其实没有必要。只要你对C语言有一些基础,对堆栈有一些印象,那么你已经拥有汇编语言的基础了。在接下来的数篇博客中,我们就会就x86汇编、数据类型、数据运行逻辑、指针、数据、类、重载运算符在汇编下是如何展开的做一些介绍,谈一些个人的看法。下面,我们就进行一些小测试,同时用汇编语言来说明一下。大家可以一起做一下。
(1) char name[] 和 char* name
- 1:
- 2: void process()
- 3: {
- 00401020 push ebp
- 00401021 mov ebp,esp
- 00401023 sub esp,4Ch
- 00401026 push ebx
- 00401027 push esi
- 00401028 push edi
- 00401029 lea edi,[ebp-4Ch]
- 0040102C mov ecx,13h
- 00401031 mov eax,0CCCCCCCCh
- 00401036 rep stos dword ptr [edi]
- 4: char name_tmp[] = {"hello"};
- 00401038 mov eax,[string "hello" (0042201c)]
- 0040103D mov dword ptr [ebp-8],eax
- 00401040 mov cx,word ptr [string "hello"+4 (00422020)]
- 00401047 mov word ptr [ebp-4],cx
- 5: char* name_glb = "hello";
- 0040104B mov dword ptr [ebp-0Ch],offset string "hello" (0042201c)
- 6: }
- 00401052 pop edi
- 00401053 pop esi
- 00401054 pop ebx
- 00401055 mov esp,ebp
- 00401057 pop ebp
- 00401058 ret
(2)apple a()和apple b
假设class apple的定义为:
- class apple
- {
- public:
- apple() {}
- ~apple() {}
- };
那么apple a()和apple b是分别怎么编译的呢?
- 9: void process()
- 10: {
- 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]
- 11: apple a();
- 12: apple b;
- 00401038 lea ecx,[ebp-4]
- 0040103B call @ILT+20(apple::apple) (00401019)
- 13: }
- 00401040 lea ecx,[ebp-4]
- 00401043 call @ILT+10(apple::~apple) (0040100f)
- 00401048 pop edi
- 00401049 pop esi
- 0040104A pop ebx
- 0040104B add esp,44h
- 0040104E cmp ebp,esp
- 00401050 call __chkesp (004010b0)
- 00401055 mov esp,ebp
- 00401057 pop ebp
- 00401058 ret
为什么apple a()这边什么也没有编译呢?原因很简单,因为编译器把apple a()看成是一个extern的函数,返回值为apple。与此相对应的apple b才是函数中真正定义的临时变量,因为在下面不远处有apple的两个函数——apple的构造函数和apple的析构函数哦。
(3)(apple*) (0) -> print()
其中class apple这样定义:
- class apple
- {
- int value;
- public:
- apple() {}
- ~apple() {}
- void print() { return;}
- };
如果0设置为apple*,那么访问函数print会有问题吗?
- 10: void process()
- 11: {
- 00401030 push ebp
- 00401031 mov ebp,esp
- 00401033 sub esp,40h
- 00401036 push ebx
- 00401037 push esi
- 00401038 push edi
- 00401039 lea edi,[ebp-40h]
- 0040103C mov ecx,10h
- 00401041 mov eax,0CCCCCCCCh
- 00401046 rep stos dword ptr [edi]
- 12: ((apple*)(0))->print();
- 00401048 xor ecx,ecx
- 0040104A call @ILT+0(apple::print) (00401005)
- 13: }
- 0040104F pop edi
- 00401050 pop esi
- 00401051 pop ebx
- 00401052 add esp,40h
- 00401055 cmp ebp,esp
- 00401057 call __chkesp (004010e0)
- 0040105C mov esp,ebp
- 0040105E pop ebp
- 0040105F ret
(4) int m = 1; int n = m++ + ++m; 那么n是多少呢?
- 10: void process()
- 11: {
- 0040D4D0 push ebp
- 0040D4D1 mov ebp,esp
- 0040D4D3 sub esp,48h
- 0040D4D6 push ebx
- 0040D4D7 push esi
- 0040D4D8 push edi
- 0040D4D9 lea edi,[ebp-48h]
- 0040D4DC mov ecx,12h
- 0040D4E1 mov eax,0CCCCCCCCh
- 0040D4E6 rep stos dword ptr [edi]
- 12: int m = 1;
- 0040D4E8 mov dword ptr [ebp-4],1
- 13: int n = m++ + ++m;
- 0040D4EF mov eax,dword ptr [ebp-4]
- 0040D4F2 add eax,1
- 0040D4F5 mov dword ptr [ebp-4],eax
- 0040D4F8 mov ecx,dword ptr [ebp-4]
- 0040D4FB add ecx,dword ptr [ebp-4]
- 0040D4FE mov dword ptr [ebp-8],ecx
- 0040D501 mov edx,dword ptr [ebp-4]
- 0040D504 add edx,1
- 0040D507 mov dword ptr [ebp-4],edx
- 14: }
- 0040D50A pop edi
- 0040D50B pop esi
- 0040D50C pop ebx
- 0040D50D mov esp,ebp
- 0040D50F pop ebp
(5) *p++和(*p)++区别是什么
- 10: void process()
- 11: {
- 0040D4D0 push ebp
- 0040D4D1 mov ebp,esp
- 0040D4D3 sub esp,48h
- 0040D4D6 push ebx
- 0040D4D7 push esi
- 0040D4D8 push edi
- 0040D4D9 lea edi,[ebp-48h]
- 0040D4DC mov ecx,12h
- 0040D4E1 mov eax,0CCCCCCCCh
- 0040D4E6 rep stos dword ptr [edi]
- 12: char data = 'a';
- 0040D4E8 mov byte ptr [ebp-4],61h
- 13: char* p = & data;
- 0040D4EC lea eax,[ebp-4]
- 0040D4EF mov dword ptr [ebp-8],eax
- 14: *p++;
- 0040D4F2 mov ecx,dword ptr [ebp-8]
- 0040D4F5 add ecx,1
- 0040D4F8 mov dword ptr [ebp-8],ecx
- 15: (*p)++;
- 0040D4FB mov edx,dword ptr [ebp-8]
- 0040D4FE mov al,byte ptr [edx]
- 0040D500 add al,1
- 0040D502 mov ecx,dword ptr [ebp-8]
- 0040D505 mov byte ptr [ecx],al
- 16: }
- 0040D507 pop edi
- 0040D508 pop esi
- 0040D509 pop ebx
- 0040D50A mov esp,ebp
- 0040D50C pop ebp
- 0040D50D ret
类似的问题还有很多,大家不妨自己试一试:
(1) 下面的union在内存是怎么安排的?gcc和vc编译的时候,分配的内存size是一样的吗?
- typedef union
- {
- char m:3;
- char n:7;
- int data;
- }value;
这里补充下上述代码的汇编形式:by orc
2: typedef union
3: {
4: char m:3;
5: char n:7;
6: int data;
7: }value;
8:
9: int main(void)
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: value a;
12: a.data=1;
00401028 mov dword ptr [ebp-4],1
13: a.m=2;
0040102F mov al,byte ptr [ebp-4]
00401032 and al,0F8h
00401034 or al,2
00401036 mov byte ptr [ebp-4],al
14: a.n=3;
00401039 mov cl,byte ptr [ebp-4]
0040103C and cl,80h
0040103F or cl,3
00401042 mov byte ptr [ebp-4],cl
15: return 0;
00401045 xor eax,eax
16: }
00401047 pop edi
00401048 pop esi
00401049 pop ebx
0040104A mov esp,ebp
0040104C pop ebp
0040104D ret
(2) 下面地址一致吗?
- char value1[] = {"hello"};
- char value2[] = {"hello"};
- char* pValue1 = “hello”;
- char* pValue2 = "hello";
- value1和value2地址一致吗?pValue1和pValue2呢?
补上汇编代码:by orc
6: char value1[] = {"hello"};
00401028 mov eax,[string "%x %c\n" (0042201c)]
0040102D mov dword ptr [ebp-8],eax
00401030 mov cx,word ptr [string "%x %c\n"+4 (00422020)]
00401037 mov word ptr [ebp-4],cx
7: char value2[] = {"hello"};
0040103B mov edx,dword ptr [string "%x %c\n" (0042201c)]
00401041 mov dword ptr [ebp-10h],edx
00401044 mov ax,[string "%x %c\n"+4 (00422020)]
0040104A mov word ptr [ebp-0Ch],ax
8: char* pValue1 = "hello";
0040104E mov dword ptr [ebp-14h],offset string "%x %c\n" (0042201c)
9: char* pValue2 = "hello";
00401055 mov dword ptr [ebp-18h],offset string "%x %c\n" (0042201c)
(3)下面一段话为什么运行错误?为什么内存泄露了?怎么修改?
- class apple
- {
- char* pName;
- public:
- apple() { pName = (char*)malloc(10);}
- ~apple() {if(NULL != pName) free(pName);}
- };
- void process()
- {
- apple a, b;
- a = b;
- }
本文详细解读了C++语言中的字符数组、指针、数据类型、类、运算符重载等特性,并通过汇编代码实例展示了这些概念的实际应用,帮助读者深入理解底层原理。
15万+

被折叠的 条评论
为什么被折叠?



