【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

(4)指针和引用

引用是C++和语言的区别之一。其实本质上说两者是一致的。朋友们可以看下面两段代码。

a)指针和指针的函数代码

void add_point(int* q)
{
(*q)++;
}
void add_ref(int& q)
{
q++;
}

b)函数的调用代码

56:       int m = 10;
004012E8   mov         dword ptr [ebp-4],0Ah
57:       add_point(&m);
004012EF   lea         eax,[ebp-4]
004012F2   push        eax
004012F3   call        @ILT+45(process) (00401032)
004012F8   add         esp,4
58:       add_ref(m);
004012FB   lea         ecx,[ebp-4]
004012FE   push        ecx
004012FF   call        @ILT+50(add_ref) (00401037)
00401304   add         esp,4
59:       return 1;
00401307   mov         eax,1
60:   }

分析一下,我们发现其实函数add_point和函数add_ref实现的功能,都是对输入的数据进行自增处理。只不过处理的时候,一个函数的入参是指针,一个函数的入参是引用。在函数调用的地方,大家可以发现指针和引用居然是一样的。首先看add_point,第一句获取m的地址复制给eax,第二句压栈处理,第三句调用函数add_point,第四句出栈回溯。同样看一下add_ref,第一句获取m的地址复制给ecx,第二句ecx压栈处理,第三句调用函数add_ref,第四句堆栈回溯处理。相信看到这里,大家就明白C++的前辈们为什么鼓励大家多多使用引用了。

(5)指针和结构体

我们在学习数据节点的时候,相信大家都学习过这样的一个数据结构定义:

typedef struct _NODE
{
int data;
struct _NODE* next;
}NODE;

当时,我们都不明白这个结构体是什么意思?其实这个定义完全修改成这样:

typedef struct _NODE
{
int data;
void* next;
}NODE;

这两个数据结构体其实是完全一致的。第一个数据保存数据,第二个数据为指针,内容为某一个数据类型的地址。这种确定的地址和void*类型的地址类型是一样的。只不过前面一种更加直接。后面一种地址的固然方便,但是使用的时候每一次都需要进行转换,很是麻烦。如果大家感兴趣,不妨是接着看下面一道题目:

typedef struct _NODE
{
struct _NODE* next;
}NODE;

我们既可以把节点NODE的地址看是NODE*,也可以堪称是NODE**,两者之间有差别吗?(其实没有区别

linux 内核代码上面有一种计算偏移值的方法,大家可以参考一下:

int offset = (int)&(((NODE*)(0))->next);

(6)class指针

class指针比较复杂,不过大家可以从一个小范例看出一些端倪:

class fruit
{
public:
fruit() {}
~fruit() {}
void print() {printf("fruit!\n");}
};
class apple : public fruit
{
public:
apple() {}
~apple() {}
void print() {printf("apple!\n");}
};
void process()
{
fruit f;
apple* a = (apple*)&f;
a->print();
fruit* b = &f;
b->print();
}

熟悉C++的朋友可以很快知道这道题目的答案了,那么为什么a和b都指向同一个地址,使用了相同的print函数,但是结果不同。我想这主要是因为两者数据类型不同的缘故。一旦指针和某一种数据类型绑在了一起,那么这个指针的所有行为事实上都已经被这种类型的数据所限定了。普通数据类型是这样,自定义的class类型也是这样。只要不是在print函数前面加上virtual,我们就会发现两个print的调用都是硬编码,和普通的函数调用无异。所以说,指针离不开数据类型,离开具体类型的地址是没有意义的。就像void*是可以原谅的,但是void却是万万不能接受的。下面的汇编代码很好的说明了这一点。

65:       fruit f;
0040132D   lea         ecx,[ebp-10h]
00401330   call        @ILT+35(fruit::fruit) (00401028)
00401335   mov         dword ptr [ebp-4],0
66:       apple* a = (apple*)&f;
0040133C   lea         eax,[ebp-10h]
0040133F   mov         dword ptr [ebp-14h],eax
67:       a->print();
00401342   mov         ecx,dword ptr [ebp-14h]
00401345   call        @ILT+0(apple::print) (00401005)
68:       fruit* b = &f;
0040134A   lea         ecx,[ebp-10h]
0040134D   mov         dword ptr [ebp-18h],ecx
69:       b->print();
00401350   mov         ecx,dword ptr [ebp-18h]
00401353   call        @ILT+25(fruit::print) (0040101e)

(全文完)

【预告: 下面一篇博客主要讨论汇编语言和流程控制】

用汇编的眼光看C++(之指针2)相关推荐

  1. 用汇编的眼光看C++(之 总结篇)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 早在八月份的时候,就陆陆续续写了二十多篇用汇编语言看C++的博客内容.在此为了做一个概括,也为 ...

  2. 用汇编的眼光看C++ (之x86汇编)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 说到用汇编的眼光看C++语言,那么怎么阅读汇编代码就成了我们需要解决的一个问题.其实,实话说, ...

  3. 用汇编的眼光看C++(之退出流程)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 无论是在判断还是在循环的过程中,通常在遇到合适的条件的时候就会退出相应的模块.跳出模块运行的方 ...

  4. 从汇编的眼光看C++(之指针拷贝)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 指针是编程人员的梦魇,对C语言的开发者是如此,对C++的开发者也是如此.特别是在C++中,如果 ...

  5. 用汇编的眼光看C++(之指针1)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 指针是我们在C/C++中经常遇到的一种数据类型.指针用的好,可以提高代码的可读性:但是如果使用 ...

  6. 用汇编的眼光看C++(之判断流程)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在我们平常的编程当中,用于判断的地方很多,但主要有下面三种方式:if-else:switch: ...

  7. 用汇编的眼光看C++(之拷贝、赋值函数)

    拷贝构造函数和复制函数是类里面比较重要的两个函数.两者有什么区别呢?其实也很简单,我们可以举个例子,加入有这样一个类的定义: [cpp] view plaincopy class apple { pu ...

  8. 用汇编的眼光看C++(之算术符重载)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 算术符重载是类的有一个特性,但是每个人使用的方法不一样.用的好,则事半功倍:但是如果不正确的使 ...

  9. 用汇编的眼光看C++(之虚函数)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 虚函数是面向对象设计中的一个重要内容.它的出现使得我们只需要相同的接口函数,并可以得到不同的生 ...

最新文章

  1. JS contcat() 连接数组 函数
  2. MySQL 语法问题:You can‘t specify target table ‘xxx‘ for update in FROM clause. 原因及解决方法
  3. Hibernate介绍
  4. git 添加未跟踪的文件
  5. Linux的openssl的安装
  6. 的引用_java中的强引用,软引用,弱引用,虚引用
  7. Java Servlet总结
  8. 基于【CentOS-7+ Ambari 2.7.0 + HDP 3.0】搭建HAWQ数据仓库02 ——使用ambari-server安装HDP...
  9. 二 vue环境搭建
  10. 解决屏蔽JS代码报错的问题
  11. 什么是端口映射?内网端口映射工具推荐
  12. 阿里云OSS云存储简介 与 基本概念
  13. 案例|工业物联网解决方案•泵站智慧云平台
  14. UWA DAY 2021 精彩盘点 | 35场技术议题掀起的思维浪潮
  15. 初学键盘计算机输入时注意,打字练习说明.doc
  16. 2-2 李宏毅2021春季机器学习教程-类神经网络训练不起来怎么办(一)局部最小值与鞍点(Local Minima and Saddle Point)
  17. 技术干货 | 基于 MindSpore 实现图像分割之平均表面距离
  18. Web前端工程师学习路径图,你掌握了多少?
  19. 《Tsinghua os mooc》第1~4讲 启动、中断、异常和系统调用
  20. Flume简介、特点、核心概念及安装

热门文章

  1. (CF#257)B. Jzzhu and Sequences
  2. 2月第3周全球五大顶级域名总量净减6.1万个 降幅明显
  3. 《LUA游戏开发实践指南》学习笔记1
  4. cocos2d-x史上最著名的诗
  5. OSO.EXE病毒专杀工具
  6. 民航重组:做大容易做强难
  7. 【转】C语言中的符号优先级
  8. Oracle v$session/v$sql 表
  9. Spring(十二)Spring之事务
  10. 【转贴】学习Linux的几点忠告