ネコナゾ娘 (・∀・)

C++点滴

C++博客 联系 聚合 管理
  6 Posts :: 0 Stories :: 0 Comments :: 0 Trackbacks
           首先说明我下面用的编译器是VC6.0 。const 是 C/C++ 的一个关键字,尤其重要的一个区别是C只是使变量常量化,而C++会在一定程度上把它当作常量。考虑下面的代码
      
const int i = 2;
  *(int*)&= 0;
printf("
%d\n", i );
  
          当文件后缀是 .c 和 .cpp 时,结果分别是 0,2 。为什么会这样,让我们看下 .cpp 时的汇编代码

00410998   mov         dword ptr [ebp-4],2                  8:        const int a = 2;
0041099F   mov         dword ptr [ebp
-4],0                  9:        *(int*)&= 0;
004109A6   push        2                                           10:       printf("%d\n",a );
004109A8   push        offset 
string "%d\t%d\n" (00427004)
004109AD   call        printf (
00410900)
         
         从上面可以看到内存中的 a 由 2 变成了 0, 下面调用 printf 的时候, 本应该把 a 的值压入堆栈,但是编译器直接把 2 压入了堆栈,太可怕了,明明内存中 a = 0了,编译器却不闻不问,这也是C++的一个特点吧,至少你修改 a 的举动失败了。当然聪明的你可以通过给 a 赋一个运行时确定的值的办法绕过编译器的自以为是,但是这肯定违背了C++的意愿。

int i ; 
scanf(
"%d"& i);
const a = i;
*(int*)&= 0;
printf(
"%d\n" , a);

       好了,不知道你有没有遇到这样的问题,如果函数的参数是结构体,函数就会傻乎乎的把整个结构体慢慢的压栈,这简直是难以想象的,所以作为一个C程序员,我总是把指针传递给函数,至于const 心情好了就添加一下,引用那是什么,从来没想过。然而,C++在这些时候总是鼓励我们使用引用,于是,我想当然得就把引用看成是一个指针(Of Course , 除了指针,还能是什么,当然你可以参考百度百科对C++引用的解释  "声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。故:对引用求地址,就是对目标变量求地址。&ra与a相等"。 这个说法是错误的,下面会告诉你 )。
      然而,今天在看《一个月挑战C++》的时候,里面对引用的解释和实例却让我有了些疑问,他肯定了引用时一个特别的指针,主要是用在函数的形式参数上 ," 例如:(int &test;),这里我们就定义了一个int类型的名为test 的引用,但是int &test; 这样的方式是不能够被编译成功的,因为引用的定义必须同时给应用进行赋值操作,这里的赋值并不是说把变量的值传递给引用,而是把引用指向变量,写成这样就对了:(int &test=变量名;)" 。 下面给出的例子是
      int a=10;  int &test=a;  test=test+2; 
你会发现&a和&test的地址显示是相同的,a和test的值显示也是一样的!这里,我并没有特别的疑惑,但是下面的例子,就有点迷茫了
       int a=10; 
       //double &test = a + 1.2f; //这句就是错误的!  
      const double &test = a + 1.2f; 
 
当然这个例子主要放在 const修饰如果用在引用上会有一个特别之处,它的奥妙就在于可以进行不同类型的对象的初始化。语法上为什么这样,就没必要深究了,但是他下面给出的解释是
  道理是这样的,const修饰过后的引用在编译器内部是这样进行变化的。

           int a=10; 
           const double &test = a + 1.2f;

  这样的一段代码在编译器认为却是下面的方式进行的

           int a=10;  
           int temp = a; 
           const double &test = temp + 1.2f;
这个怎么看都跟没解释一样,然后我就自己看了下汇编,我认为等价的C++代码应该更像是
           register double temp = (double)a +1.2f;
           const double &test = temp;       
然后我又试了下下面的代码   double  a = 2; double &b = a; double c = 0; 输出了下 &a , &c 的值,发现他们相差了12个字节,其中8字节被一个double类型占用,也就是说   double &b 占用了4个字节,刚刚好是一个指针的大小,而查看汇编也说明了那个地方存的就是 a 的地址(这也说明了引用是会在栈上分配内存的,大小是一个指针占用的空间)。

8:        int a = 2;
00410998   mov         dword ptr [ebp-4],2      ; [ebp - 4] 就是 a
9:        int &= a;
0041099F   lea         eax,[ebp
-4]                  ; 直接取 a 的地址                             
004109A2   mov         dword ptr [ebp
-8],eax   ; 把 a 的地址就这么赋给b了, 所以 b 是一个指向 a 的指针
10:       b = 0;
004109A5   mov         ecx,dword ptr [ebp
-8]   ;如果 b 是int 型变量,这里就应该是 mov dword ptr[ebp - 8],0 了
004109A8   mov         dword ptr [ecx],
0


为什么存的是指针,使用时却是当double呢!很简单,因为编译器遇到引用,就自动把 指针指向的数据转换成需要的类型。所以在参数传递中使用 引用 和 指针 在本质上是一样的,不一样的地方在于,你无法传递 NULL 指针,从而减少了对参数合理性的检查!
          




        
        

  
     
posted on 2012-03-22 17:34 neko::nazo 阅读(194) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理