++运算符在C/C++与C#/JAVA中的差异

5 篇文章 0 订阅

++ 运算符

The increment operator (++) increments its operand by 1. The increment operator can appear before or after its operand
增量运算符 (++) 将操作数加 1。增量运算符可以出现在操作数之前或之后

The first form is a prefix increment operation. The result of the operation is the value of the operand after it has been incremented.
第一种形式是前缀增量操作。该操作的结果是操作数加 1 之后的值。

The second form is a postfix increment operation. The result of the operation is the value of the operand before it has been incremented.
第二种形式是后缀增量操作。该运算的结果是操作数增加之前的值。



以上是MSDN对++运算符的定义。此定义在C/C++、C#、JAVA (以下简称它们) 中的表现形式是一致的,故i++与++i在相应语言的编译器中的表现也是一样的。
标题“++ 运算符在C/C++、C#、JAVA中的差异”中的差异不是语言本身的差异,而是相应编译器的差异。

刚刚说过,i++ 与 ++i 在它们的编译器中表现是一样的,但i=i++; 与i=++i;呢 i=++i 这个没有分歧,有分歧的是i=i++ 在C/C++ 中

i=i++; i 自增前的值就是这个表达式的值,在表达式执行后 i自增1 如果 i=1 的话,i=i++ 就等于1 ,i=i++ 执行后 i=2。

int i=1;  printf("%d/n",i = i++); printf("%d/n",i);   会打印出1和2 就是说会对i先赋值,然后对i自增1。

而在C#与JAVA中  i=i++ 等于 i 的值,而 i 的值会变化但仍然是之前的值。因为C#与JAVA的编译器会严格遵循运算符优先级,首先对=右侧求值也就是 i 的值,

然后将 i 值入栈(将1入栈),之后优先级的缘故 ++ 在 = 之前执行 i 先自增1 变成2,然后将栈里的1 赋值给 i , i 这时又变回了1。

相对于C/C++的编译器来说C#与JAVA的编译器的做法更容易解释也更合理,在我看生成的汇编代码前,以为C/C++编译器也会严格遵循优先级,

故猜测是将 i 的地址入栈而不是直接将值入栈所以出现的不一致,但看过之后证明我的猜测是错误的,C/C++编译器是将值放在寄存器中,

但与C#和JAVA的编译器不同的是它未严格遵守运算符优先级,就我目前掌握到的这属于C/C++编译器undefined的范畴,

它们的执行逻辑随编译器的不同而不同。所以千万不要在C/C++程序中依赖求值顺序,否则会死的很惨。

看下面一段代码

int  j, i = 3
j
= (i + 3 ) *++ i; 
printf(
" %d/n " , i); 
printf(
" %d/n " , j);

在知道结果前,不妨先演算一下。结果是4,28 你算对了么? 而在C#与JAVA中则是4,24。

相应的汇编代码  

  int  j, i= 3 ;

   
mov     DWORD PTR _i$[ebp],  3             //将3存储到_i$[ebp]中

   j=(i+
3 )*++i ;

   
mov     eax, DWORD PTR _i$[ebp]      // 将_i$[ebp]的值放寄存器eax  
   
add     eax,  1                                       // eax+ 1  结果放在eax中 
   
mov     DWORD PTR _i$[ebp], eax      // eax的值放在_i$[ebp]中 
   
mov     ecx, DWORD PTR _i$[ebp]      // 将_i$[ebp]的值放寄存器ecx 
   
add     ecx,  3                                       // ecx+ 3  结果放在ecx中 
   
imul     ecx, DWORD PTR _i$[ebp]      //  ecx*_i$[ebp] 
   
mov     DWORD PTR _j$[ebp], ecx      //  将ecx的值放到_j$[ebp]中

生成的IL

[ 2 int32  j,[ 3 int32  i

int j, i=
3 ;

  
IL_000e:    ldc.i4.3           // 将3入栈                                         栈中元素3 
   IL_000f:     stloc.3            // 对栈顶元素做弹出操作,并存储到相应下标的变量中      栈中无元素 

j=(i+
3 )*++i;

  
IL_0010:    ldloc.3            // 对相应下标的变量做取值操作,并入栈                  栈中元素3 
   IL_0011:    ldc.i4.3           // 将3入栈                                          栈中元素3,3 
   IL_0012:    add                // 对栈顶两个元素依次做弹出并相加,结果入栈             栈中元素6 
   IL_0013:    ldloc.3            // 对相应下标的变量做取值操作,并入栈                   栈中元素6,3 
   IL_0014:    ldc.i4.1           // 将1入栈                                          栈中元素6,3,1 
   IL_0015:    add                // 对栈顶两个元素依次做弹出并相加,结果入栈              栈中元素6,4 
   IL_0016:    dup                // 对栈顶元素做复制操作并入栈                          栈中元素6,4,4 
   IL_0017:    stloc.3            // 对栈顶元素做弹出操作,并存储到相应下标的变量中         栈中元素6,4 
   IL_0018:    mul                 // 对栈顶两个元素依次做弹出并相乘,结果入栈             栈中元素24 
   IL_0019:    stloc.2            // 对栈顶元素做弹出操作,并存储到相应下标的变量中         栈中无元素

这里没有提供相关的JAVA字节码,但由于JVM和CLR都是 Stack-Based VM,所以只是具体指令不一样,指令的运算逻辑与运算方式都是一样的,可以参看IL部分。

我们将j=(i+3)*++i; 换成j=++i*(i+3);看看会发生什么。相应的汇编代码没有任何改变,IL却是大不相同,输出的结果都是4,28

相关的IL 

IL_000e:    ldc.i4.3  
IL_000f:    stloc.3  
IL_0010:    ldloc.3  
IL_0011:    ldc.i4.1  
IL_0012:    add  
IL_0013:    dup  
IL_0014:    stloc.3  
IL_0015:    ldloc.3  
IL_0016:    ldc.i4.3  
IL_0017:    add  
IL_0018:    mul  
IL_0019:    stloc.2  

相信聪明的你一定可以通过之前IL的注解演算出此段IL的运算过程,我就不赘述了。

 

最后是CSDN里某同学的问题 “int index=1;count=10;执行index=(index++) % count;后输出结果为何还是1”

后输出结果为何还是1 指的是输出index还是1

相关IL

[ 0 int32  index,[ 1 int32  count

  
IL_0001:    ldc.i4.1  
  
IL_0002:    stloc.0  
  
IL_0003:    ldc.i4.s     10  
  
IL_0005:    stloc.1  
  
IL_0006:    ldloc.0  
  
IL_0007:    dup  
  
IL_0008:    ldc.i4.1  
  
IL_0009:    add  
  
IL_000a:    stloc.0  
  
IL_000b:    ldloc.1  
  
IL_000c:    rem  
  
IL_000d:    stloc.0  

相关汇编代码   

int  index= 1 ,count= 10 ;

    
mov     DWORD PTR _index$[ebp],  1  
    
mov     DWORD PTR _count$[ebp],  10          ;  0000000aH

index = (index++) % count
;

    
mov     eax, DWORD PTR _index$[ebp] 
    
cdq  
    
idiv     DWORD PTR _count$[ebp] 
    
mov     DWORD PTR _index$[ebp], edx 
    
mov     eax, DWORD PTR _index$[ebp] 
    
add     eax,  1  
    
mov     DWORD PTR _index$[ebp], eax

通过上面的IL 你能否回答他的问题呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值