C語言的型別系統-編碼, 型別轉換及其規範
C語言的型別系統
——————
組合語言將儲存器看成一個虛擬儲存器,即將儲存器看成一個大的位元組陣列,組合語言並沒有提供型別系統. C語言將位元組陣列抽象成不同長度的位元組陣列.本文介紹C語言的型別系統以及型別之間相互轉換的原則.
C語言的資料型別
————
C語言的型別是相當豐富的,它提供多種型別. C語言的資料型別具體有:
1.基本型別:整型(short/int/long/longlong (C99)),浮點型(float/double/long double(C99)),字元型(char-可以歸整型),列舉型.
2.構造型別:陣列,結構,聯合.
3.指標型別.
4.空型別.
C標準明確規定
型別 |
ILP32規範(IA32) |
ILP32對應的Intel資料型別 |
LP64(x86-64) |
LP64對應的Intel資料型別 |
char |
1 |
位元組 |
1 |
位元組 |
short |
2 |
字 |
2 |
字 |
int |
4 |
雙字 |
4 |
雙字 |
long |
4 |
雙字 |
8 |
四字 |
long long |
8 |
----- |
8 |
四字 |
指標 |
4 |
雙字 |
8 |
四字 |
float |
4 |
單精度 |
4 |
單精度 |
double |
8 |
雙精度 |
8 |
雙精度 |
long double |
10/12 |
擴充套件精度 |
10/16 |
擴充套件精度 |
本文是IA32,故採用ILP32規範進行分析.
計算機編碼
————
現代計算機資訊的表示,儲存,傳輸都是都是通過二級制來完成的(具體的原因, 元芳懂得).通過二進位制數字系統, 我們可以進行編碼,諸如對整數,負數,浮點數近似值,字元等進行編碼.
計算機的三種重要的數字表示:
1.無符號(unsigned)編碼.---->對應C語言的無符號整數.
假設一個整數資料型別有
B2Uw(x) =∑(i=0…w-1)xi2i
2.補碼(two's-complement)編碼.---->對應C語言的整數.
假設一個整數資料型別有w位.設位向量x=[xw-1, xw-1,…,x0].定義一個函式B2Tw(Binary toTwo's-complement).
B2Tw(x) =-xw-12w-1+∑(i=0…w-2)xi2i (將最高有效位解釋為負權)
3.浮點數(floating-point)編碼.----->對應C語言的float/double/longdouble.
C標準沒有規定浮點數必須使用IEEE 754標準,但是現代計算機普通使用IEEE754.詳見IEEE 754浮點數的表示(也可以參考csapp的第二章).
C語言的型別轉換
————
C語言的型別轉換分為隱式型別轉換和強制型別轉換.
1.型別轉換的原理.
(1).同類型的有符號和無符號數之間的轉換(位模式的重新解釋).
典型案例: unsigned<->int
有符號和無符號之間轉換時候,位模式並沒有變化.
(2).符號位擴充套件(保證值不變->可以使用數學歸納法證明).
典型案例: short->int; unsigned short-> unsigned int
C規範並沒有要求符號位擴充套件,但是符號位擴充套件能夠保證有符號的數值不變.所以大多數實現都是有符號擴充套件.
(3). 截斷原理.
典型案例: int->short; unsigned int->unsigned short
有符號和無符號的截斷都是高位截斷.
(4).轉換原理.
典型案例: int->float/double; float->double
瞭解了IEEE754浮點數標準,很容易理解int, float,double之間如何轉換. int->float/double首先就是要規格化,然後舍入.再轉換.
a. int->float(32位->32位).顯然,不會溢位,但是會舍入(精度損失).
b. int/float->double.不會溢位,也不會舍入(不會有精度損失).
c. double->float.值可能會溢位(+Infinity or -Infinity),可能會舍入.
d. float/double->int.可能會溢位(C標準沒有規範會溢位成什麼結果. Intel相容機通常是[100…00]),向0舍入. (+1.9->1,-1.9->-1).
2. C標準的規範.
(1).隱式型別轉換(Implicit Conversion)[3種]
(2).強制型別轉換(Explicit Conversion or Type Cast)
3.編譯器處理型別轉換
例如:
src_t v;
dest_t*p;
*p =(dest_t)v;
假定: v放在%eax, p放在%edx.
src_t |
dest_t |
指令 |
型別 |
int |
int |
movl %eax, (%edx) |
- |
char |
int |
movsbl %al, (%edx) |
符號位擴充套件 |
char |
unsigned |
movsbl %al, (%edx) |
char->int->unsigned |
unsigned char |
int |
movzbl %al, (%edx) |
位擴充套件 |
int |
char |
movb %al, (%edx) |
截斷 |
unsigned |
unsigned char |
movb %al, (%edx) |
截斷 |
unsigned |
int |
movl %eax, (%edx) |
位模式重新解釋 |
reference: