轉載請注明出處
http://blog.csdn.net/pony_maggie/article/details/37535577
作者:小馬
先看兩段代碼, 一個是C,一個是java。
~~~
int _tmain(int argc, _TCHAR* argv[])
{
char b = 0x83;
short s1 = (short)b;
short s2 = (short)(b&0xff);
printf("s1 = %d\n", s1);
printf("s2 = %d\n", s2);
return 0;
}
~~~
~~~
public static void main(String[] args)
{
byte b = (byte)0x83;
short s1 = (short)b;
short s2 = (short)(b&0xff);
System.out.printf("s1 = %d\n", s1);
System.out.printf("s2 = %d\n", s2);
}
~~~
運行結果其實是一樣的:
s1 = -125
s2 = 131
用兩種語言,是想說明它的通用性,表示這個特性跟語言本身無關。那么原因是什么呢?
首先,第二個結果才是我們期望的,這個應該都同意(至少大部分情況下都是這樣)。其次如果變量b是正數(這里是負數,因為char表示有符號數,0x83最高位是1,表示負數),S1和S2的結果是相等的。
所以,問題的核心其實還是變量b的這個符號位。計算機里從低精度數向高精度數轉換時,比如這里從char到short, 肯定會在前面擴展一些bit位,從而達到高精度數的長度。那么擴展時,是補0還是補1呢?這里有個原則就是,有符號數擴展符號位,也就是1,無符號數擴展0。
再看看上面的代碼,s1其實是0xff83, 是個負數,它表示的值就是-125(注意0xff83是補碼表示,計算原值要換成原碼)。而s2是0x0083, 因為它強制與上了0xff,其實就是與上了0x00ff。這樣就把高字節轉成了0x00,消除了符號位。
為了證明上面的理論,可以做一個實驗,把代碼改成這樣:
~~~
int _tmain(int argc, _TCHAR* argv[])
{
char b = 0x83;
short s1 = (short)b;
short s2 = (short)(b&0xffff);
printf("s1 = %d\n", s1);
printf("s2 = %d\n", s2);
return 0;
}
~~~
運行,結果是s1=s2=-125。這也支持了上面的理論分析。
趁熱打鐵,再看一個示例:
~~~
int _tmain(int argc, _TCHAR* argv[])
{
char a = 0xff;
if (a == 0xff)
{
printf("equal\n");
}
return 0;
}
~~~
運行的結果是, “equal”并沒有打印出來。你可能已經分析出原因了。字符a在和0xff比較時,被隱式的轉換成int(因為0xff是整型),然后a做了符號位擴展,變為0xffffffff, 這個值和0x000000ff比較,當然是不等的。
我希望已經講清楚了,歡迎拍磚。