0000
作家
作家
  • 铜币143枚
  • 威望34点
  • 贡献值1点
阅读:1171回复:12

i++與i--的陷阱

楼主#
更多 发布于:2005-10-29 10:27
昨天意外發現一個奇怪的現象,i++和i--, 看起來相當簡單~

僞代碼:
// i++
int i = 0;
i = i++-1;
print(i);

// i--
int i = 0;
i = i---1;
print(i);

這裏兩個運算分別進行後, i 分別是多少?
學過C的一眼就能看出, 第一個結果是 0, 第二個結果是 -2.

但是如果是在JAVA裏, 問題出現了~
以下是測試代碼:
// i ++
public class Ipuzzle{
 public static void main(String[] args){
   int i = 0;
   i = i++ -1;
  System.out.println("i = "+i);
 }
}

// i --
public class Ipuzzle{
 public static void main(String[] args){
   int i = 0;
   i = i-- -1;
  System.out.println("i = "+i);
 }
}

這時不幸發生了, 輸出的結果居然都是 i = -1 (oops!)
而相同的內容用C描述並且用GCC編譯並運行的結果卻和推測的一樣, 分別是 0 和 -2.

這是什麽原因呢?(為了避免4C的服務器當掉導致偶寫的內容全都泡湯, 先發一下再回複吧-_-#)
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
0000
作家
作家
  • 铜币143枚
  • 威望34点
  • 贡献值1点
1C#
发布于:2005-10-29 10:47
Re:i++與i--的陷阱
以下是我對上面原因的推測, 可能不對~請達人解釋一下~~

對於C:
運算過程 i = i++-1 可以作以下分解:
// i = 0; //前文提到
1. i = 0 - 1 //運算後 i = -1
2. i = i + 1 // i++, 這和平時的理解都是一致的, 運算後 i = -1

而對於java
運算過程 i = i++-1 作這樣的分解:
// i = 0; //前文提到
1. int j = 0 - 1; //即 int j = i - 1, 此時虛擬機創建了另一個對象來進行運算
2. i = i + 1; // i ++, 此時 i = 1.
3. i = j; //虛擬機把指向 j 的值的指針作為 i 的指針, 好像說的不是很清楚~`過程如下:

假定在第一步運算的時候創建了另一個對象(j), 那麽運算後的內容就應該是
 pointer i ---------------> (int) 1
 pointer j ---------------> (int) -1
然後 i 和 j 指針的指向進行了互換, 這樣結果 i 就是 -1 了.
但是為什麽要互換呢? 因為我們要求的數是 i 而不是 j ,事實上我們從來沒有顯式地引入第二個變量, 所以此虛擬機為了服從我們, 就把它們兩個互換了~它總不能告訴我們說"對不起, 我這裏有兩個 i ,你想要我輸出哪一個?" 所以問題就出現了~~

有這種想法是因為在字符串的改變過程中的操作有些相似
比如說:
String str = "hello";
str = "hello Mr.0000";
實際上現在內存裏有兩個 String 的對象, 分別是 "hello" 和 "hello Mr.0000"
在把 str 的值改到 "hello Mr.0000" 的過程中虛擬機做了以下操作:
Create String "hello" //這是第一步, String str = "hello"
str ----> "hello" //變量str指向 "hello"
Create String "hello Mr.0000"
str --> "hello Mr.0000" //把變量str指向新的字符串 "hello Mr.0000", 而舊的"hello"而等待GC來處理.

但是這只是對 Object 的操作, 而至於對 primity(這個單詞好像寫錯了?不好好學習-_-##) 類型數據是不是這樣處理就不清楚了~~
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
0000
作家
作家
  • 铜币143枚
  • 威望34点
  • 贡献值1点
2C#
发布于:2005-10-29 10:49
Re:i++與i--的陷阱
任意拿起一本JAVAXXX教程的第一章都會堂皇地說"萬物皆對象"(當然也不排除是在第二章~~). 我倒覺得這裏還有一句話就是萬物皆指針也許更合適一點~~~
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
0000
作家
作家
  • 铜币143枚
  • 威望34点
  • 贡献值1点
3C#
发布于:2005-10-29 10:51
Re:i++與i--的陷阱
BTW:
說明一下測試環境:
JAVA: JDK1.5
C: 這個偶就不知道了~~單位的服務器,應該是 Suse 的系統~~, GCC的版本也不知道~
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
瘦人
著名写手
著名写手
  • 铜币23枚
  • 威望2点
  • 贡献值2点
4C#
发布于:2005-10-29 21:37
Re:i++與i--的陷阱
我是这么理解的
i++ 就是先运算完 再自己加上1
所以
 int i = 0;
 i = i++ -1;  // i=0-1=-1
然后自己再运算一次加1=0,但是已经不影响 i++ -1的结果了.
所以说 i 的值就是-1,
这就是i++和++i 的区别吧, 在自己加1上有个顺序问题,
如果换成以下这样,虽然结果还不能是0,但就是这个意思
public class Ipuzzle{
public static void main(String[] args){
   int i = 0;
   int a = i++ -1;
  System.out.println("a = "+a);
  System.out.println("i = "+i);
}
}
 a=-1
  i=1
唉呀呀,反正我就是这个意思,也不知道怎么表达好了,哈哈[em149] [ 2005-10-29 22:18:53 瘦人 修改 ]
Look up the star...
0000
作家
作家
  • 铜币143枚
  • 威望34点
  • 贡献值1点
5C#
发布于:2005-10-30 09:17
Re:i++與i--的陷阱
但是c里头的结果可不一样哦~
也就是说在java里,
 int i = 0;
 i = i++ -1;
这个运算创建了两个i,而在c里只有一个i~
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
瘦人
著名写手
著名写手
  • 铜币23枚
  • 威望2点
  • 贡献值2点
6C#
发布于:2005-10-30 09:41
Re:i++與i--的陷阱
java源于c而高于c[em061]
Look up the star...
suchasplus
作家
作家
  • 铜币16枚
  • 威望11点
  • 贡献值1点
7C#
发布于:2005-11-02 09:29
Re:i++與i--的陷阱
还是不习惯java的方式~
The history of these days will be written in blood... By crushing the armies of our enemy, by seizing the weapons they thought to turn against us, we were fighting for our very existence!
ApH
ApH
知名人士
知名人士
  • 铜币0枚
  • 威望0点
  • 贡献值0点
8C#
发布于:2005-11-03 00:47
Re:i++與i--的陷阱
http://www.wait4c.com/bbs/message.asp?id=168734
0000
作家
作家
  • 铜币143枚
  • 威望34点
  • 贡献值1点
9C#
发布于:2005-11-03 18:21
Re:i++與i--的陷阱
哈哈~当年偶才 68 帖就狂妄到口算~~
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
0000
作家
作家
  • 铜币143枚
  • 威望34点
  • 贡献值1点
10C#
发布于:2005-11-03 18:23
Re:i++與i--的陷阱
You are modifying a variable in an expression that uses it twice. That's
undefined behaviour, just like x = v+v[i++];
-_-#什么叫没有定义嘛~~
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
ApH
ApH
知名人士
知名人士
  • 铜币0枚
  • 威望0点
  • 贡献值0点
11C#
发布于:2005-11-05 20:20
Re:i++與i--的陷阱
就是说别这么写,也别研究。
0000
作家
作家
  • 铜币143枚
  • 威望34点
  • 贡献值1点
12C#
发布于:2005-11-14 12:45
Re:i++與i--的陷阱
周末和同学讨论到这个问题, 觉得用JAVA的 "传值" 的概念更好解释.
把操作符看作是一个 方法, 用传值(与此相对, C/C++中的传引用)的观点正好解释这个问题~
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
游客

返回顶部