C語言中強制數據類型轉換(轉)

原文地址不詳函數

字符型變量的值實質上是一個8位的整數值,所以取值範圍通常是-128~127,char型變量也能夠加修飾符unsigned,則unsigned char 型變量的取值範圍是0~255(有些機器把char型當作unsighed char型對待, 取值範圍老是0~255)。
● 若是一個運算符兩邊的運算數類型不一樣,先要將其轉換爲相同的類型,即較低類型轉換爲較高類型,而後再參加運算,轉換規則以下圖所示。
double ←── float 高

long

unsigned

int ←── char,short 低
● 圖中橫向箭頭表示必須的轉換,如兩個float型數參加運算,雖然它們類型相同,但仍要先轉成double型再進行運算結果亦爲double型。 縱向箭頭表示當運算符兩邊的運算數爲不一樣類型時的轉換,如一個long 型數據與一個int型數據一塊兒運算,須要先將int型數據轉換爲long型, 而後二者再進行運算,結果爲long型。全部這些轉換都是由系統自動進行的, 使用時你只需從中瞭解結果的類型便可。這些轉換能夠說是自動的,但然,C語言也提供了以顯式的形式強制轉換類型的機制。
當較低類型的數據轉換爲較高類型時,通常只是形式上有所改變, 而不影響數據的實質內容, 而較高類型的數據轉換爲較低類型時則可能有些數據丟失。
賦值中的類型轉換
當賦值運算符兩邊的運算對象類型不一樣時,將要發生類型轉換, 轉換的規則是:把賦值運算符右側表達式的類型轉換爲左側變量的類型。具體的轉換以下:
(1) 浮點型與整型 
將浮點數(單雙精度)轉換爲整數時,將捨棄浮點數的小數部分, 只保留整數部分。
將整型值賦給浮點型變量,數值不變,只將形式改成浮點形式, 即小數點後帶若干個0。注意:賦值時的類型轉換其實是強制的。
(2) 單、雙精度浮點型 
● 因爲C語言中的浮點值老是用雙精度表示的,因此float 型數據只是在尾部加0延長爲doub1e型數據參加運算,而後直接賦值。doub1e型數據轉換爲float型時,經過截尾數來實現,截斷前要進行四捨五入操做。 
(3) char型與int型 
int型數值賦給char型變量時,只保留其最低8位,高位部分捨棄。 
char型數值賦給int型變量時, 一些編譯程序無論其值大小都做正數處理,而另外一些編譯程序在轉換時,若char型數據值大於127,就做爲負數處理。對於使用者來說,若是原來char型數據取正值,轉換後仍爲正值;若是原來char型值可正可負,則轉換後也仍然保持原值, 只是數據的內部表示形式有所不一樣。 
(4) int型與1ong型 
● long型數據賦給int型變量時,將低16位值送給int型變量,而將高16 位截斷捨棄。(這裏假定int型佔兩個字節)。 
將int型數據送給long型變量時,其外部值保持不變,而內部形式有所改變。 
(5) 無符號整數 
將一個unsigned型數據賦給一個佔據一樣長度存儲單元的整型變量時(如:unsigned→int、unsigned long→long,unsigned short→short) ,原值照賦,內部的存儲方式不變,但外部值卻可能改變。
將一個非unsigned整型數據賦給長度相同的unsigned型變量時, 內部存儲形式不變,但外部表示時老是無符號的。 
/*例:賦值運算符舉例 */
main()
{ unsigned a,b;
   int i,j;
   a=65535;
   i=-1;
   j=a;
   b=i;
   printf("(unsigned)%u→(int)%d\n",a,j);
   printf("(int)%d→(unsigned)%u\n",i,b);
}
運行結果爲:
(unsigned)65535→(int)-1
(int)-1→(unsigned)65535

● 計算機中數據用補碼錶示,int型量最高位是符號位,爲1時表示負值,爲0時表示正值。若是一個無符號數的值小於32768則最高位爲0,賦給 int型變量後、獲得正值。若是無符號數大於等於32768,則最高位爲1, 賦給整型變量後就獲得一個負整數值。反之,當一個負整數賦給unsigned 型變量時,獲得的無符號值是一個大於32768的值。 
● C語言這種賦值時的類型轉換形式可能會令人感到不精密和不嚴格,由於無論表達式的值怎樣,系統都自動將其轉爲賦值運算符左部變量的類型。 
● 而轉變後數據可能有所不一樣,在不加註意時就可能帶來錯誤。 這確實是個缺點,也遭到許多人們批評。但不該忘記的是:c面言最初是爲了替代彙編語言而設計的,因此類型變換比較隨意。固然, 用強制類型轉換是一個好習慣,這樣,至少從程序上能夠看出想幹什麼。

C語言規定,不一樣類型的數據須要轉換成同一類型後纔可進行計算,在整型、實型和字符型數據之間經過類型轉換即可以進行混合運算(但不是全部類型之間均可以進行轉換) 

.當混合不一樣類型的變量進行計算時,即可能會發生類型轉換 
相同類型的數據在轉換時有規則可循: 
   字符必須先轉換爲整數(C語言規定字符類型數據和整型數據之間能夠通用) 
   short型轉換爲int型(同屬於整型) 
   float型數據在運算時一概轉換爲雙精度(double)型,以提升運算精度(同屬於實型) 
   賦值時,一概是右部值轉換爲左部類型 
[注] 
     當整型數據和雙精度數據進行運算時,C先將整型數據轉換成雙精度型數據,再進行運算,結果爲雙精度類型數據 
     當字符型數據和實型數據進行運算時,C先將字符型數據轉換成實型數據,而後進行計算,結果爲實型數據
2.4  數據類型轉換在C語言的表達式中,准許對不一樣類型的數值型數據進行某一操做或混合運算。當不一樣類型的數據進行操做時,應當首先將其轉換成相同的數據類型,而後進行操做。數據類型轉換有兩種形式,即隱式類型轉換和顯示類型轉換。
2.4.1  隱式類型轉換所謂隱式類型轉換就是在編譯時由編譯程序按照必定規則自動完成,而不需人爲干預。所以,在表達式中若是有不一樣類型的數據參與同一運算時,編譯器就在編譯時自動按照規定的規則將其轉換爲相同的數據類型。
C語言規定的轉換規則是由低級向高級轉換。例如,若是一個操做符帶有兩個類型不一樣的操做數時,那麼在操做以前行先將較低的類型轉換爲較高的類型,而後進行運算,運算結果是較高的類型。更確切地說,對於每個算術運算符,則遵循圖2-2所示的規則。

圖2-2  數據類型轉換規則之一
圖2-2  數據類型轉換規則之一
注意:在表達式中,全部的float類型都轉換爲double型以提升運算精度。
在賦值語句中,若是賦值號左右兩端的類型不一樣,則將賦值號右邊的值轉換爲賦值號左邊的類型,其結果類型仍是左邊類型。
由於函數參數是表達式,所以,當參數傳遞給函數時,也發生類型轉換。具體地說,char和short均轉換爲int;float轉換爲double。這就是爲何咱們把函數參數說明爲int和double,儘管調用函數時用char和float .
也能夠將圖2-2所示的規則用圖2-3表示。圖2-3中的水平箭頭表示一定轉換,縱向箭頭表示兩個操做對象類型不一樣時的轉換方向。

圖2-3  數據類型轉換規則之二
下面舉行說明類型轉換的規則。例如執行:
x=100+'a'+1.5 * u+f/'b'-s * 3.1415926
其中,u爲unsigned型,f爲float型,s爲short型,x爲float型。式中右面表達式按以下步驟處理:
(1)首先將'a'、'b'和s換成int,將1.5和f轉換爲double型。
(2)計算100+'a',因'a'已轉換爲int型,因而此運算結果爲197。
(3)計算1.5*u,因爲1.5已轉換爲double,u是unsigned型,因而首先u轉換爲double,而後進行運算,運算結果爲double。
(4)計算197+1.5 * u,先將197轉換爲double(如197.00…00),其結果爲double。
(5)計算f/ 'b',f已轉換爲double,'b'已轉換爲int,因而先將'b'再轉換爲double,其結果爲double。
(6)計算(197+1.5 * u)+f / 'b',者均爲double,因而結果也爲double。
(7)計算s * 3.1415926,先將s由int轉換爲double,而後進行運算,其結果爲double。
(8)最後與前面得的結果相減,結果爲double。
(9)最後將表達式的結果轉換爲float並賦給x。
2.4.2  顯式類型轉換顯示類型轉換又叫強制類型轉換,它不是按照前面所述的轉換規則進行轉換,而是直接將某數據轉換成指定的類型。這可在不少狀況下簡化轉換。例如,
int i;

i=i+9.801
按照隱式處理方式,在處理i=i+9.801時,首先i轉換爲double型,而後進行相加,結果爲double型,再將double型轉換爲整型賦給i。
int i;

i=i+(int)9.801
這時直接將9.801轉換成整型,而後與i相加,再把結果賦給i。這樣可把二次轉換簡化爲一次轉換。
顯示類型轉換的方法是在被轉換對象(或表達式)前加類型標識符,其格式是:
(類型標識符)表達式
例如,有以下程序段:
main()

int a,b;
float c;
b=a+int(c);
printf("b=d% \ n",b);

在上述程序的運行過程當中,在執行語句b=a+int(c)時,將c的值臨時強制性轉化爲int型,但變量c在系統中仍爲實型變量,這一點很重要,很多初學者在這個問題上忽略了這個問題。spa


2.5  運算符和表達式設計

2.5.1  運算符和表達式概述指針

1.表達式一個表達式包含一個或多個操做,操做的對象稱做運算元(或叫做操做數),而操做自己經過運算符體現的。例如a、a-b、c=9.801等都是一個表達式。
一個表達式完成一個或多個操做,最終獲得一個結果,而結果的數據類型由參加運算的操做決定。最簡單的表達式是隻含一個常量或變量的表達式,即只含一個操做數而不含運算符。
C語言中表達式的種類十分豐富,主要有以下一些:
n         算術表達式:進行通常的計算。
n         賦值表達式:進行賦值操做。
n         關係表達式:進行比較判斷。
n         邏輯表達式:進行邏輯比較判斷。
n         條件表達式:進行條件知足與否的判斷。
n         逗號表達式:其實是一種複雜運算,能夠包含多個算術表達式。
2.C語言的操做符C語言的特色之一是具備豐富和使用靈活的運算符,歸納起來它有以下的幾類運算符:
n         算術運算符。
n         賦值運算符(包括符合賦值運算符)。
n         關係運算符。
n         邏輯運算符。
n         條件運算符。
n         逗號運算符。
n         位運算符。
n         指針運算符。
n         求字節運算符(能夠歸併到函數的應用中去,它是經過函數sizeof()來進行運算的)。
n         強制類型轉換運算符。
這些運算符如表2-4所示。
表2-4 C語言中的運算符
名稱操做符自增,自減
+ +,- -
邏輯與、或、非
&&,︱︱,!
續表2-4  
名稱操做符指針操做及引用
*,&
加、減、乘、除、求模運算
+,-,*,/,%
關係操做符
<,<=,>,>=,==,!=
按位與、或、異或、求反
&,丨,^,~
逗號表達式

類型轉換
()
移位運算
< <,> >
條件運算
?:
求佔用的字節數
sizeof
賦值
=,+ =,- =,*=,/ =,% =
先看程序:
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char**argv){
     unsigned int right = 1;
     char left = -1;
     if(left < right)printf("%d < %d\n", left, right);
     else if(left == right)printf("%d = %d\n", left, right);
     else printf("%d > %d\n", left, right);
     system("PAUSE");
     return 0;
}
運行結果是:-1 > 1
解釋:按步驟進行.
1. 若是其中一個操做數爲long double類型,則另外一個操做數被轉換爲long double.
2. 不然,若是其中一個操做數爲double, 則另外一個操做數被轉換爲double.
3. 不然,若是其中一個操做數爲float, 則另外一個操做數也轉換爲float.
4. 不然,兩個操做數進行 "整型升級":
     a. 若是其中一個操做數爲unsigned long int, 則另外一個操做數也被視爲unsigned long int.
     b. 不然,若是其中一個操做數爲long int,而另外一個操做數類型是unsigned int, 而且long int可以表示unsigned int的全部值,則另外一個操做數也被視爲long int;若是long int不能表示unsigned int的全部值,則兩個數都被視爲unsigned long int.
     c. 不然, 若是其中一個操做數是long int,則另外一個操做數也被視爲long int.
     d. 不然, 若是其中一個操做數是unsigned int, 則另外一個操做數也被視爲unsigned int.
     e. 不然, 兩個操做數都被視爲int.對象

例題1:blog

char a=0xb6;
short b=0xb600;
int c=0xb6000000;

if(a==0xb6) puts("a");  //左邊爲有符號數,右邊無符號數
if(b==0xb600) puts("b");
if(c==0xb6000000) puts("c");

//結果:gcc只打印出c(char默認爲signed char)

==爲一種運算符,則兩邊的值會進行類型轉換爲int型。見第一個圖get

gcc將三條語句解釋爲編譯器

if(0xffffffb6==0x000000b6) puts("a");
if(0xffffb600==0x0000b600) puts("b");
if(0xb6000000==0xb6000000) puts("c");

 

例題2:io

一樣是有關「整形提高」編譯

無符號數擴位補0

有符號書擴位補符號位,符號位爲0則補0爲1則補1

#include <stdio.h>
int main()
{
    char  ca;
    unsigned char ucb;
    unsigned short usc;
 
    ca = 128;      //0x80
    ucb =128;      //0x80
 
    usc = ca + ucb;   //0x0000=0xffffff80 + 0x00000080 而後截斷取低四位(後同)
    printf("%d\n", usc);
   
    usc = ca + (short)ucb; //0x0000=0xffffff80 + 0x0000(0080) unsigned char -> short ->int
    printf("%d\n", usc);
 
    usc = (unsigned char)ca + ucb; //0x0100 = 0x000000(80) + 0x00000080
    printf("%d\n", usc);
 
    usc = ca + (char)ucb;  //0xff00 = 0xffffff80 + 0xffffff(80) 
  printf("%d\n", usc); 
  getchar();
  return EXIT_SUCCESS;
}

結果:0  0  256  65280

同時能夠看到char<->unsigned char, short<->unsigned short 轉換中,與類型等長的部分實際上是相同的,不一樣的是截斷去掉的那部分

char       -128     127

unsigned char      0        256

0-127之間兩者沒有差異     

例如:

unsigned char uca=128;

printf("%x\n",(char)uca);  //打印出來: ffffff80,unsigned char -> char若越界的話會整形提高。

相關文章
相關標籤/搜索