【C 語言入門】176.合法的隱性轉型

整數和整數之間,浮點數和浮點數之間,他們之間的型別不是完全一樣的。

但是整數和整數之間、浮點數和浮點數之間是可以互轉的。

但其中有可能造成精度上的問題,以及由於溢位造成未定義行為。

未定義行為的風險是存在的,不過大部分情況下,是允許的。

浮點數和整數之間是可以互轉的,浮點數轉整數時會無條件省去。

同樣的也可能造成精度上的問題,以及由於溢位造成未定義行為。

int intVar = 3;
char charVar = '3';
float floatVar = 3.5f;
double doubleVar = 3.5;

//同類型別內互轉 (整數與整數間、浮點數與浮點數間)
floatVar = doubleVar; //(float) = (double)(O)
intVar = charVar;     //(int) = (char)    (O)

//整數與浮點數間互轉
intVar = doubleVar;   //(int) = (double)  (O:無條件捨去)
doubleVar = intVar;   //(double) = (int)  (O)

我們之前也提過一個陣列可以隱性轉型成一個整數的指標。

int v[3];
int *n;
const int p;

//陣列可以隱性轉型成指向一個元素的指標
n = v;   //(int *) = (int [3]) (O)

相反的,指標是不能隱性轉型成陣列的。

int v[3];
int *n;
const int p;

//陣列可以隱性轉型成指向一個元素的指標
n = v;   //(int *) = (int [3]) (O)
v = n;   //(int [3]) = (int *) (X)

然後我們介紹了指向某個陣列的指標可以隱性轉型成指向某個 const 的型別的指標。

int v[3];
int *n;
const int p;

//陣列可以隱性轉型成指向一個元素的指標
n = v;   //(int *) = (int [3]) (O)
v = n;   //(int [3]) = (int *) (X)

// Type * 可以隱性轉型成 const Type *
p = n;   //(const int *) = (int *) (O)

如果把 const 型別的指標轉成某一個型別的指標的話,這樣的轉型很可能是有問題的。

代表原本不可以改的變成可以改。

int v[3];
int *n;
const int p;

//陣列可以隱性轉型成指向一個元素的指標
n = v;   //(int *) = (int [3]) (O)
v = n;   //(int [3]) = (int *) (X)

// Type * 可以隱性轉型成 const Type *
p = n;   //(const int *) = (int *) (O)

n = p;   //(int *) = (const int *)(?)

整數指標無法存在 double

我們也有提到,整數的指標是不能存在 double 的指標裡的,因為 C 語言並沒有去定義這樣的行為。

當指向的型別不一樣的時候,原則上是不能互轉的。

但是有個例外。

例外- void指標

這個例外就是叫 void 的指標,基本上任何一個型別的指標,它可以轉成voidPointer,也就是 void 指標。

而 void 指標也可以轉型成任意的型別的指標。

#include <stdio.h>

int main()
{
    int intVar =3;
    void *voidPtr = &intVar;
    int *intPtr = voidPtr;
    printf("%d\n", *intPtr);
    return 0;
}

也就是說,當兩個指標型別互換轉時,其中一個是 void 指標的話,大部分情況下都會轉換成功。這是 C 語言少數定義的一個行為。

我們可以把 void Pointer 想像成泛用型別。

在 C 語言,我們在講泛用型別的時候,很多時候是用 void 指標的概念來處理的。

簡單來說,不同型別要轉換只能使用 void 指標,不過不一定能轉成功。

void 指標特色

void 指標有個很大的特色就是它沒辦法被取址。

原則上沒有任何變數的型別是 void 的,因此你不能對 void 的指標取值。

#include <stdio.h>

int main()
{
    int intVar =3;
    void *voidPtr = &intVar;
    printf("%d\n", *voidPtr);  //(X : 編譯失敗)
    return 0;
}

Leave a Comment

Your email address will not be published. Required fields are marked *