深入理解C語言中的型別轉換

2020-10-19 11:00:56

隱式轉換

基本型別轉換

整形提升

表示式計算時,整型會首先提升到int型別,當int型別表示的範圍不夠時,會提升為unsigned int型別。c語言中可以進行整型提升的包括bool,char,short及其對應的無符號型別。下面例子中,不管是bool,char還是short型別,在進行算術運算時,運算結果大小都是4個位元組,這是因為編譯器會預設對這些整型進行提升,轉為4個位元組再進行運算。

int main()
{
    bool b1 = true;
    bool b2 = true;
    // output: 4 2
    cout << sizeof(b1 + b2) << " " << b1 + b2 << endl;

    char c1 = 'a';
    char c2 = 'b';
    // output 4 195
    cout << sizeof(c1 + c2) << " " << c1 + c2 << endl;

    short s1 = INT16_MAX;
    short s2 = 1;
    // output 4 32768
    cout << sizeof(s1 + s2) << " " << s1 + s2 << endl;

    return 0;
}

算術轉換

  • 整型和浮點數相加得到浮點型;
  • 有符號整型和有符號整型相加得到其中較大的有符號整型;
  • 無符號整型和無符號整型相加得到其中較大的無符號整型;
  • 有符號整型和無符號整型相加得到較大空間的型別,如果有符號整型空間大,則結果為有符號整型,如果無符號整型空間大,則結果為無符號整型,如果有符號整型和無符號整型空間相等,則結果為無符號整型。

總結來說,算術轉換會往較大空間型別的方向轉換;如果空間一樣,則會往浮點型或者無符號方向轉換。

int i1 = INT32_MAX;
long long ll1 = 1;
// output 8 2147483648
cout << sizeof(i1 + ll1) << " " << i1 + ll1 << endl;

unsigned int ui1 = 1;
// output 4 2147483648
cout << sizeof(i1 + ui1) << " " << i1 + ui1 << endl;

int i2 = 1;
// output 4 -2147483648 整數溢位
cout << sizeof(i1 + i2) << " " << i1 + i2 << endl;

指標轉換

任何指標型別都可以隱式轉換成void*型別,反之不成立。

int a = 0;
int* pa = &a;
void* pb = pa;    // 正確
pa = pb;          // 編譯錯誤

顯示轉換

第一部分中提到了C語言中基本型別之間的轉換以及任意指標轉換為void指標,這些轉換都可以隱式地進行,編譯器預設幫助開發者操作,不會報錯。然而,對於void指標轉換為某個具體型別的指標或者任意兩種不是void型別指標之間的轉換來說,編譯器都會丟擲錯誤。需要明確的一點是,C語言中任意型別指標之間都是可以完成轉換的,只不過編譯器覺得這個轉換很不安全,不會幫我們暗地裡操作,需要程式開發者個人判定安全性,使用顯示轉換。有人可能會覺得第一部分中的轉換也很不安全,比如double轉為int,會使得數值損失精度,事實確實如此,但相比任意指標間的轉換來說,這種轉換的風險小得多,因此對於第一部分的情況,編譯器支援預設轉換。

int a = 0;
void* pa = &a;
int* pb = (int*)pa;
// 正確,輸出0
cout << *pb << endl;

// 正確,輸出空,因為a為0,其第一個位元組為0,在char型變數中,表示空
char* pc = (char*)pb;
cout << *pc << endl;