int a和(int &)a的区别(转)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了int a和(int &)a的区别(转)相关的知识,希望对你有一定的参考价值。
(1)语言的类型的强制转换不会修改原来的数据,会另外的开辟一个临时的或者程序中指定的空间来存储强制转换后的值。
(2)C++引用的实现是在符号表中动了手脚,把自己的变量符号对应的内存地址写成了它所引用的那个变量的内存地址了。
(3)C++的cout函数的执行,是根据变量的名称找到对应的内存地址,然后根据变量的类型从内存中抓取相应的数据。
有了上面的两个知识点,看下面的程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include <iostream> using namespace std; int main() { float a = 1.0f; cout << ( int )a << endl; cout << ( int &)a << endl; cout << endl; float b = 0.0f; cout << ( int )b << endl; cout << ( int &)b << endl; return 0; } |
程序执行结果:
首先先来看(int&)a是什么意思:
这句话的意思就是给a声明了一个匿名的引用,并且这个引用是临时的,int类型的。会再符号表中增加这么一个条目
(int&)a这个表达式就返回这个临时的变量temp,它是a的引用,只不过类型是int的。
所以在执行
cout << (int &)a << endl;
这句话的时候,cout就根据temp的地址和类型抓取数据。
看完了(int&)a,那么(int)a呢?似乎很熟悉,但是真的知道具体的过程吗。也许吧,看下面:
前面说到,对数据的类型强制转换,不会修改原来的数据的内容。所以(int)a这个表达式会再符号表中产生这样一个条目:
看到了,这里的临时变量的内存地址不是原来的地址,是操作系统又重新分配了一块临时的内存地址。这块内存地址的值就是变量类型强制转换后的值。
这样可以看出来这两个语句一个是在原来的内存基础上,把float类型的数据以int输出,一个是强制转转数据类型,从新开辟了一块新的存储空间放转换后的值,然后再输出。
上面分析的是程序的原理,应该是这么实现的。但是编译器为了减少访问内存的次数(符号表也在内存中的哦~),经常用寄存器来处理这些临时的变量,看这个程序的汇编代码:
--- C:\\Program Files\\Microsoft Visual Studio\\MyProjects\\TestThread\\testThread.cpp -----------------------------------------------------------------
1: #include <iostream>
2: using namespace std;
3:
4: int main()
5: {
00401780 push ebp
00401781 mov ebp,esp
00401783 sub esp,48h
00401786 push ebx
00401787 push esi
00401788 push edi
00401789 lea edi,[ebp-48h]
0040178C mov ecx,12h
00401791 mov eax,0CCCCCCCCh
00401796 rep stos dword ptr [edi]
6: float a = 1.0f;
00401798 mov dword ptr [ebp-4],3F800000h//这里看到,1.0在内存中的存储方式,是单精度浮点数的存储方式
7: cout << (int)a << endl;
0040179F push offset @ILT+195(std::endl) (004010c8)
004017A4 fld dword ptr [ebp-4]//把这个内存单元中的数据以浮点数方式加载到浮点寄存器中
004017A7 call __ftol (0042133c)//这个函数就把浮点数寄存器中的数据转换成了int类型,并把结果放在了eax寄存器中。转换完之后的结果00000001h
004017AC push eax//输出eax中的数据
004017AD mov ecx,offset std::cout (0047ff88)
004017B2 call @ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)//ILT是Debug模式下函数的入口表,Release下就直接调用函数了,245是int类型数据的输出函数序号
004017B7 mov ecx,eax
004017B9 call @ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
8: cout << (int &)a << endl;
004017BE push offset @ILT+195(std::endl) (004010c8)
004017C3 mov eax,dword ptr [ebp-4]//直接把a的值原封不动的copy到eax寄存去中
004017C6 push eax//输出eax中的数据
004017C7 mov ecx,offset std::cout (0047ff88)
004017CC call @ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)
004017D1 mov ecx,eax
004017D3 call @ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
9: cout << a << endl;
004017D8 push offset @ILT+195(std::endl) (004010c8)
004017DD mov ecx,dword ptr [ebp-4]
004017E0 push ecx
004017E1 mov ecx,offset std::cout (0047ff88)
004017E6 call @ILT+285(std::basic_ostream<char,std::char_traits<char> >::operator<<) (00401122)//285是float类型数据的输出函数序号
004017EB mov ecx,eax
004017ED call @ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
10:
11: cout << endl << endl;
004017F2 push offset @ILT+195(std::endl) (004010c8)
004017F7 push offset @ILT+195(std::endl) (004010c8)
004017FC mov ecx,offset std::cout (0047ff88)
00401801 call @ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
00401806 mov ecx,eax
00401808 call @ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
12:
13: float b = 0.0f;
0040180D mov dword ptr [ebp-8],0
14: cout << (int)b << endl;
00401814 push offset @ILT+195(std::endl) (004010c8)
00401819 fld dword ptr [ebp-8]
0040181C call __ftol (0042133c)
00401821 push eax
00401822 mov ecx,offset std::cout (0047ff88)
00401827 call @ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)
0040182C mov ecx,eax
0040182E call @ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
15: cout << (int &)b << endl;
00401833 push offset @ILT+195(std::endl) (004010c8)
00401838 mov edx,dword ptr [ebp-8]
0040183B push edx
0040183C mov ecx,offset std::cout (0047ff88)
00401841 call @ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)
00401846 mov ecx,eax
00401848 call @ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
16:
17: return 0;
0040184D xor eax,eax
18: }
从汇编语言中看到,(int)a是要经过类型强制转换的,并且把转换后的值放在寄存器中输出,(int&)a直接把原来的数据copy到一个寄存器中输出。
重要的说明一下:
符号表是在编译阶段产生的,上面说的temp和temp1这样的临时的变量也是在编译的时候都已经弄到了符号表中,只不过它 的作用域仅仅的就是那句话。不是在执行阶段在往符号表中增加的条目。
最后再说一个知识点:单精度浮点数、双精度浮点数的存储。
单精度和双精度浮点数的存储方式和int类型的存储方式是完全不同的,int的1在内存中的存储方式是00000001h,int的0是00000000h,但是浮点数要用符号位+阶码+尾数的方式存储。
以单精度的float为例:
它的形式是1.M * 2E-127,其中E是指数为的移码形式。所以对于float的1.0,尾数M=0,阶码E=127,符号位是0,所以对应的机器码是:3F800000h。
提示:为什么浮点数阶码部分要用移码?
(1)使用移码方便运算。2的指数部分有正有负,使用了移码之后,2的指数依然有正有负,但是数据的真正的存储位E就完全是正的值了,没有了负值,这样能加快运算。
(2)为了统一浮点数的0和整数的0。整数0的各个二进制位是全0(公认的了),但是如果不用移码,浮点数的全0是1,用了移码之后,这个是就是1.0 * 20-127,由于这个数太小了,这时会发生溢出,也就是0。
from:http://www.cnblogs.com/stemon/p/4421178.html
以上是关于int a和(int &)a的区别(转)的主要内容,如果未能解决你的问题,请参考以下文章
佩特来项目经验小集合___组合查询存储过程,报错 "varchar JBID='' 转换成数据类型 int 时失败"(示例代(代码