码迷,mamicode.com
首页 > 其他好文 > 详细

关于i++与++i的学习讨论!

时间:2017-10-06 00:02:57      阅读:243      评论:0      收藏:0      [点我收藏+]

标签:存储   返回值   中断   问题   左值   阶段   tar   答案   情况   

先谈容易的知识点

  区别两个

      1、 i++ 返回原来的值,++i 返回加1后的值。
      2、 i++ 不能作为左值,而++i 可以。

重点说下第二点。
首先解释下什么是左值

 左值是对应内存中有确定存储地址的对象的表达式的值,而右值是所有不是左值的表达式的值。

  左值与右值的根本区别在于是否允许取地址&运算符获得对应的内存地址。

比如,
int i = 0;
int *p1 = &(++i); //正确
int *p2 = &(i++); //错误

++i = 1; //正确
i++ = 5; //错误

为什么(i++)不能做左值,而(++i)可以
// 前缀形式:
int& int::operator++() //这里返回的是一个引用形式,就是说函数返回值也可以作为一个左值使用
{//函数本身无参,意味着是在自身空间内增加1的
  *this += 1;  // 增加
  return *this;  // 取回值
}
====================================================================================================================================
//后缀形式:
const int int::operator++(int) //函数返回值是一个非左值型的,与前缀形式的差别所在。
{//函数带参,说明有另外的空间开辟
  int oldValue = *this;  // 取回值
  ++(*this);  // 增加
  return oldValue;  // 返回被取回的值
}
如上所示,i++ 最后返回的是一个临时变量,而临时变量是右值。so不能返回引用 。 why!  自己想!
 
 
关于原子性的讨论继续!!!!!!!!!

  都不是原子操作

1.i++分为三个阶段:

          内存到寄存器         寄存器自增         写回内存

这三个阶段中间都可以被中断分离开.

 2.++i首先要看编译器是怎么编译的,

某些编译器比如VC在非优化版本中会编译为以下汇编代码:

__asm
{
        mov  eax,  dword ptr[i]
        inc eax
        mov dword ptr[i], eax
}
这种情况下,必定不是原子操作,不加锁互斥是不行的。
假设加了优化参数,那么是否一定会编译为“inc dword ptr[i]”呢?答案是否定的,这要看编译器心情,如果++i的结果还要被使用的话,那么一定不会被编译为“inc dword ptr[i]”的形式。
那么假设如果编译成了“inc dword ptr[i]”,这是原子操作,是否就不需要加锁了呢?如果在单核机器上,不加锁不会有问题,但到了多核机器上,这个不加锁同样会带来严重后果,两个CPU可以同时执行inc指令,但是两个执行以后,却可能出现只自加了一次。
真正可以确保不“额外”加锁的汇编指令是“lock inc dword ptr[i]”,lock前缀可以暂时锁住总线,这时候其他CPU是无法访问相应数据的。但是目前没有任何一个编译器会将++int编译为这种形式。

在多核的机器上,cpu在读取内存i时也会可能发生同时读取到同一值,这就导致两次自增,实际只增加了一次。

 

 
 

关于i++与++i的学习讨论!

标签:存储   返回值   中断   问题   左值   阶段   tar   答案   情况   

原文地址:http://www.cnblogs.com/zhangkele/p/7630288.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!