当写C语言写多了,自然就喜欢C++了----小话C++(1)(二)

2014-11-24 12:01:30 · 作者: · 浏览: 1
。如下例子:
[cpp]
1. #include
2. #include
3.
4. #define COUT_ENDL(str) std::cout << #str << " is " << (str) << std::endl;
5.
6. void swap(int &a, int &b)
7. {
8. int temp = a;
9. a = b;
10. b = temp;
11. }
12.
13. void swap(int *pa, int *pb)
14. {
15. int temp = *pa;
16. *pa = *pb;
17. *pb = temp;
18. }
19.
20.
21. int main()
22. {
23. int a = 1, b = 2;
24. swap(a, b);
25. COUT_ENDL(a)
26. COUT_ENDL(b)
27.
28. a = 1, b = 2;
29. swap(&a, &b);
30. COUT_ENDL(a)
31. COUT_ENDL(b)
32.
33. return 0;
34. }
保存为main.cpp.
void swap(int &a, int &b);函数的汇编如下:
[cpp]
1. 0x0000000100000c00 <_Z4swapRiS_+0>: push %rbp
2. 0x0000000100000c01 <_Z4swapRiS_+1>: mov %rsp,%rbp
3. 0x0000000100000c04 <_Z4swapRiS_+4>: mov %rdi,-0x8(%rbp)
4. 0x0000000100000c08 <_Z4swapRiS_+8>: mov %rsi,-0x10(%rbp)
5. 0x0000000100000c0c <_Z4swapRiS_+12>: mov -0x8(%rbp),%rsi
6. 0x0000000100000c10 <_Z4swapRiS_+16>: mov (%rsi),%eax
7. 0x0000000100000c12 <_Z4swapRiS_+18>: mov %eax,-0x14(%rbp)
8. 0x0000000100000c15 <_Z4swapRiS_+21>: mov -0x10(%rbp),%rsi
9. 0x0000000100000c19 <_Z4swapRiS_+25>: mov (%rsi),%eax
10. 0x0000000100000c1b <_Z4swapRiS_+27>: mov -0x8(%rbp),%rsi
11. 0x0000000100000c1f <_Z4swapRiS_+31>: mov %eax,(%rsi)
12. 0x0000000100000c21 <_Z4swapRiS_+33>: mov -0x14(%rbp),%eax
13. 0x0000000100000c24 <_Z4swapRiS_+36>: mov -0x10(%rbp),%rsi
14. 0x0000000100000c28 <_Z4swapRiS_+40>: mov %eax,(%rsi)
15. 0x0000000100000c2a <_Z4swapRiS_+42>: pop %rbp
16. 0x0000000100000c2b <_Z4swapRiS_+43>: retq

void swap(int *pa, int *pb);函数的汇编如下:
[cpp]
1. 0x0000000100000c30 <_Z4swapPiS_+0>: push %rbp
2. 0x0000000100000c31 <_Z4swapPiS_+1>: mov %rsp,%rbp
3. 0x0000000100000c34 <_Z4swapPiS_+4>: mov %rdi,-0x8(%rbp)
4. 0x0000000100000c38 <_Z4swapPiS_+8>: mov %rsi,-0x10(%rbp)
5. 0x0000000100000c3c <_Z4swapPiS_+12>: mov -0x8(%rbp),%rsi
6. 0x0000000100000c40 <_Z4swapPiS_+16>: mov (%rsi),%eax
7. 0x0000000100000c42 <_Z4swapPiS_+18>: mov %eax,-0x14(%rbp)
8. 0x0000000100000c45 <_Z4swapPiS_+21>: mov -0x10(%rbp),%rsi
9. 0x0000000100000c49 <_Z4swapPiS_+25>: mov (%rsi),%eax
10. 0x0000000100000c4b <_Z4swapPiS_+27>: mov -0x8(%rbp),%rsi
11. 0x0000000100000c4f <_Z4swapPiS_+31>: mov %eax,(%rsi)
12. 0x0000000100000c51 <_Z4swapPiS_+33>: mov -0x14(%rbp),%eax
13. 0x0000000100000c54 <_Z4swapPiS_+36>: mov -0x10(%rbp),%rsi
14. 0x0000000100000c58 <_Z4swapPiS_+40>: mov %eax,(%rsi)
15. 0x0000000100000c5a <_Z4swapPiS_+42>: pop %rbp
16. 0x0000000100000c5b <_Z4swapPiS_+43>: retq

可以看出,两段汇编代码完全一致。其实也可以这么理解,编译器对于引用其实就是默认看成传指针,当然这取决于编译器,不能确定的是所有使用引用和指针方式的代码的汇编代码都一致,但是至少它们最终完成的功能是一致的。

Q: 对于像上面的代码,同为swap函数,编译器最终如何将它们区分开?
A: 既然有不同,编译器自然能把它们区分开。正如上面的汇编中显示的,第一个swap函数在编译器内部的名称是_Z4swapRiS_,第二个swap函数的名称是_Z4swapPiS_.
使用nm命令查看生成的可执行文件内部的符号表(在这里工程默认生成的可执行为testForCpp):
\

可以看出,确实存在这两个名称。对于为什么会是这样的名字,这里只能提供一个常用的命名规则,一般会采用"返回值+(命名空间)+函数名+参数形式",具体对于不同编译器处理不尽相同。

Q: c++中的输入输出,cout, cin到底和printf、scanf函数有什么区别?
A: 从一个角度来说,cout和cin是对象;printf和scanf是函数;另外一个角度来说,cout的效率很可能比printf函数要低,因为它内部封装了许多函数,为了安全原因或者模块化的考虑,而printf相对比较直接。对于cout是否调用printf函数,应该说不能完全确定,尽管有说法是如此,也许是兼容的原因,不同平台应该有不同的考虑。
如下是cout等变量的声明:
[cpp]
1. extern istream cin; ///< Linked to standard input
2. extern ostream cout; ///< Linked to standard output
3. extern ostream cerr; ///< Linked to standard error (unbuffered)
4. extern ostream clog; ///< Linked to standard error (buffered)

Q: 对于虚函数可以实现动态绑定,可以认为c++是动态语言吗?
A: 按照动态语言的基本概念,标准c++算不上,它依然是要求比较严格的编译型语言。对于动态绑定,c++也仅仅用静态的方式实现了略微有些动态特性的功能。实现动态绑定,一般都有虚表的支持,编译器会根据类以及继承体系中虚函数函数的名称,组装出一个虚表,然后根据调用代码的具体含义简单地调用对应虚表位置的函数。虽然,表面看起来很单纯,实际上,编译器早可以计算出实际调用的是什么(当然除了参数为基类指针的单独函数除外,这也是为什么要有虚表的原因之一).
如果这个特性可以看成动态的话,那么c++也就是具备了一点点动态特性的语言而已。

xichen

摘自 陈曦的分享