在執行算術運算時,計算機比c語言的限制更多。為了讓計算機執行算術運算,通常要求運算元有相同的大小(即位的數量相同),並且要求儲存的方式也相同。計算機可能可以直接將兩個16位整數相加,但是不能直接將16位整數和32位整數相加,也不能直接將32位整數和32位浮點數相加。另一方面,c語言允許在表示式中混合使用基本資料型別。在單獨乙個表示式中可以組合整數、浮點數,甚至是字元。當然,在這種情況下c語言編譯器可能需要生成一些指令將某些運算元轉換成不同型別,使得硬體可以對表示式進行計算。例如,如果對16位int型數和32位long int型數進行加法操作,那麼編譯器將安排把16位int型值轉換成32位值。如果是int型資料和float型資料進行加法操作,那麼編譯器將安排把int型值轉換成為float格式。這個轉換過程稍微複雜一些,因為int型值和float型值的儲存方式不同。因為編譯器可以自動處理這些轉換而無需程式設計師介入,所以這類轉換稱為隱式轉換(implicit conversion)。c語言還允許程式設計師通過使用強制運算子執行顯式轉換(explicit conversion)。首先討論隱式轉換,,執行隱式轉換的規則有些複雜,主要是因為c語言有大量不同的基本資料型別(6種整型和3種浮點型,這還不包括字元型)。
當發生下列情況時會進行隱式轉換:
.當算術表示式或邏輯表示式中運算元的型別不相同時。(c語言執行所謂的常用算術轉換。)
.當賦值運算子右側表示式的型別和左側變數的型別不匹配時。
.當函式呼叫中使用的引數型別與其對應的引數的型別不匹配時。
.當return語句中表示式的型別和函式返回值的型別不匹配時。
隱式型別轉換規則:
c語言自動轉換不同型別的行為稱之為隱式型別轉換 ,轉換的基本原則是:低精度型別向高精度型別轉換,具體是:
int -> unsigned int -> long -> unsigned long -> long long -> unsigned long long -> float -> double -> long double
注意,上面的順序並不一定適用於你的機器,比如當int和long具有相同字長時,unsigned int的精度就會比long的精度高(事實上大多數針對32機的編譯器都是如此)。另外需要注意的一點是並沒有將char和short型寫入上式,原因是他們可以被提公升到int也可能被提公升到unsigned int。
提公升資料的精度通常是乙個平滑無損害的過程,但是降低資料的精度可能導致真正的問題。原因很簡單:乙個較低精度的型別可能不夠大,不能存放乙個具有更高精度的完整的資料。乙個1位元組的char變數可以存放整數101但不能存放整數12345。當把浮點型別資料轉換為整數型別時,他們被趨零截尾或捨入。
當把有符號運算元和無符號運算元整合時,會通過把符號位看成數的位的方法把有符號運算元"轉換"成無符號的值.這條規則可能會導致某些隱蔽的程式設計錯誤。
假設int型的變數i的值為-10,而且unsigned int型的變數u的值為10。如果用<運算子比較變數i和變u,那麼期望的結果應該是1(真)。但是,在比較前,變數i轉換成為unsigned int型別。因為負數不能被表示成無符號整數,所以轉換後的數值將不再為-10,而是乙個大的正數(將變數i中的位看作是無符號數).因此i
由於此類陷阱的存在,所以最好盡最避免使用無符號整數,特別是不要把它和有符號整數混合使用。
先來看一段簡單的**:
執行結果:
randy@ubuntu:~/c_language$ ./a.out
now i = 7.
是不是很奇怪?為什麼沒有打出line13的x = ?。
是這樣的。這個小例子有三點值得注意:
1.sizeof()是運算子,返回型別是無符號的,即非負數。
2.if語句在singned int和unsigned int之間進行判斷語句,根據c語言的整型提公升規則,int -> unsigned int。
3.i = -1被公升級為無符號型,值究竟是多少?這要用到整型轉換規則:k&r上這樣解釋,將任何整數轉換為某種指定的無符號數型別數的方法是:以該無符號數型別能夠表示的最大值加1為摸,找出與此整數同餘的最小的非負值。聽著很拗口,其實說白了,只要知道原整數的二進位制表達方法,再用要即將轉換的型別去解析,就得到公升級後的值了。 比如-1,負數在計算機裡用補碼表示為0xffffffff,那公升級成無符號型之後,值就是0xffffffff,顯然比total_elements(7)大。
強制型別轉換:
通常我們應該避免自動型別轉換,當我們需要手動指定乙個準確的資料型別時,我們可以用強制型別轉換機制來達到我們的目的,使用方法很簡單,在需要強制轉換型別的變數或常量前面加上(type),例如(double)i; 即把變數 i 強制轉換成double型。
思考下面這個例子:
long int i;
int j = 10000;
i = j*j; /*wrong*/
乍看之下,這條語句沒有問題。表示式j*j的值是1000000,並且變數i是long int型的,所
以i應該能很容易地儲存這種大小的值,不是嗎?問題是,當兩個int型值相乘時,結果也應該
是int型別的,但是j*j的結果太大,以致於在某些機器上無法表示成int型別.在這樣的機器
上,會給變數i賦乙個無意義的值。幸運的是,可以使用強制型別轉換避免這種問題的發生:
i=(long int)j*j
因為強制運算子的優先順序高於*,所以第乙個變數j會被轉換成long int型別,同時也迫使第
二個j進行轉換。
注意語句
i==(long int)(j*j)/**wrong***/
是不對的,因為溢位在強制型別轉換之前就己經發生了。
q&a:
問:如果"溢位"會發生什麼?比如,兩個數相加的結果過大而無法儲存.
答:這取決於數是有符號型的還是無符號型的。當溢位發生在有符號數的操作上時,依據c語言的標準,
結果是"未定義的"。我們無法準確說出結果是什麼,因為這依賴於機器的行為。程式甚至可能會
異常中斷(對除以零的典型反應)。
但是,當溢位發生在無符號數的操作上時,結果是定義了的:可以獲得正確答案對2n進行取模運算
的結果,這裡的n是用於儲存結果使用的位數。例如,如果用1加上無符號的16位數65535,那麼結
果肯定是65536 (已經溢位,但計算機能正確表示其值).
學習推薦路線:
C語言資料型別轉換
自動轉換發生在不同資料型別的量混合運算時,由編譯系統自動完成。自動轉換遵循以下規則 若參與運算量的型別不同,則先轉換成同一型別,然後進行運算。轉換按資料長度增加的方向進行,以保證精度不降低。如int型和long型運算時,先把int量轉成long型後再進行運算。所有的浮點運算都是以雙精度進行的,即使僅...
C語言資料型別轉換
變數的資料型別是可以轉換的。轉換的方法有兩種,一種是自動轉換,一種是強制轉換。自動轉換發生在不同資料型別的量混合運算時,由編譯系統自動完成。自動轉換遵循以下規則 若參與運算量的型別不同,則先轉換成同一型別,然後進行運算。轉換按資料長度增加的方向進行,以保證精度不降低。如int型和long型運算時,先...
C語言資料型別轉換
資料型別轉換就是將資料 變數 表示式的結果 從一種型別轉換到另一種型別。例如,為了儲存小數你可以將int型別的變數轉換為double型別。資料型別轉換的一般格式為 type name expressiontype name為要轉換到的資料型別,expression為表示式。例如 float a 把a...