亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

C 語言中的類型轉換

我們在前面學習了 C 語言的數據類型,那么變量在參與運算的時候類型是始終如一不變的嗎?

帶著這個疑問,我們可以先看一個例子:

#include <stdio.h>

#define typename(x) _Generic((x),        /* Get the name of a type */             \
                                                                                  \
        _Bool: "_Bool",                  unsigned char: "unsigned char",          \
         char: "char",                     signed char: "signed char",            \
    short int: "short int",         unsigned short int: "unsigned short int",     \
          int: "int",                     unsigned int: "unsigned int",           \
     long int: "long int",           unsigned long int: "unsigned long int",      \
long long int: "long long int", unsigned long long int: "unsigned long long int", \
        float: "float",                         double: "double",                 \
  long double: "long double",                   char *: "pointer to char",        \
       void *: "pointer to void",                int *: "pointer to int",         \
      default: "other")

int main()
{
    int a=1,b=2;
    float c=3.14159,d=0;
    printf("a type: %s, b type: %s, c type: %s, d type: %s\n",typename(a),typename(b),typename(c),typename(d));
    a=b+c;
    printf("a=b+c, a=%d\n",a);
    printf("type (b+c): %s\n",typename(b+c));
    d=b+c;
    printf("d=b+c, d=%f\n",d);
    return 0;
}

經過編譯運行后得到如下的結果:

Tips:有關如何編譯運行的內容請參考前面的章節。
Tips:同時值得注意的是,這個程序中的 _Generic 來自于 C11 標準中,所以在你之前可能看到的 C 語言的書籍中是沒有的。請大家不要使用過于古老的編譯器,請使用推薦的較新的編譯器。也就是支持 C11 以上標準的編譯器。具體情況可以參照你們所選擇的編譯器的手冊?;蛘咧苯舆x擇 GCC 7 及更新版本的編譯器。

a type: int, b type: int, c type: float, d type: float
a=b+c, a=5
type (b+c): float
d=b+c, d=5.141590

這里面的 a, b 變量為整形,而 c 和 d 都是浮點型。那么當一個整形和一個浮點型相加的時候會發生什么呢?這就是我們今天要介紹的內容。

1. 隱式類型轉換

C 語言是強類型語言,也就是說不同類型的數據之間是不能進行運算的。必須保持一致的類型才能進行運算。也就是說在這個不同數據類型的計算過程中,C 語言自動進行了一次類型轉換,使得兩個變量的數據類型一致,才能進行相關的計算。這種自動的轉換,也稱之為隱式類型轉換。

從前面提及的例子還可以看出,我們定義的數據類型,在不同的類型的數據運算結束后,并沒有發生改變,也就是數據類型保持著我們最開始定義時候的類型。這時會發生丟棄精度的事情,也就是上面例子中小數點后面的數值就會消失。

那么這種隱式的轉換有什么規律可循嗎?

下面的表格就展示了類型轉換的規律,當在計算過程中,數值類型不一致的時候,就會發生自動的類型轉換,轉換的類型是將表格中處于下方的較低優先級的數據類型,向表格上方的較高優先級的數據類型進行轉換。

級別 數據類型
1 long double
2 double
3 float
4 unsigned long long
5 long long
6 unsigned long
7 long
8 unsigned int
9 int
10 char short int

根據這個表格我們就可以看出之前的轉換中,int 與 float 類型進行計算,編譯器會自動將 int 類型轉換為 float 類型進行計算。從而使得運算在相同的數據類型間進行。

2. 顯式類型轉換

如果說隱式類型轉換是編譯器自動進行的類型轉換,那么顯式類型轉換,則是我們人為的進行數據類型的轉換,這里可以理解為是一種強制的類型的轉換,這種轉換將不再遵守上面的轉換規則,而是按照我們人為的標明的類型進行轉換。

就是在我們需要指定類型的變量前加上數據類型,并用圓括號包裹。例如: (int)a, (float)b, (long)c 等。

下面我們通過一個示例程序來看一下顯式類型轉換:

實例演示
預覽 復制
復制成功!
#include <stdio.h>

#define typename(x) _Generic((x),        /* Get the name of a type */             \
                                                                                  \
        _Bool: "_Bool",                  unsigned char: "unsigned char",          \
         char: "char",                     signed char: "signed char",            \
    short int: "short int",         unsigned short int: "unsigned short int",     \
          int: "int",                     unsigned int: "unsigned int",           \
     long int: "long int",           unsigned long int: "unsigned long int",      \
long long int: "long long int", unsigned long long int: "unsigned long long int", \
        float: "float",                         double: "double",                 \
  long double: "long double",                   char *: "pointer to char",        \
       void *: "pointer to void",                int *: "pointer to int",         \
      default: "other")

int main()
{
    int a=1,b=2;
    float c=3.14159,d=0;
    printf("a type: %s, b type: %s, c type: %s, d type: %s\n",typename(a),typename(b),typename(c),typename(d));
    a=(float)b+(float)c;
    printf("a=b+c, a=%d\n",a);
    printf("type (b+c): %s\n",typename((int)b+(int)c));
    d=(int)b+(int)c;
    printf("d=b+c, d=%f\n",d);
    return 0;
}#include <stdio.h>

#define typename(x) _Generic((x),        /* Get the name of a type */             \
                                                                                  \
        _Bool: "_Bool",                  unsigned char: "unsigned char",          \
         char: "char",                     signed char: "signed char",            \
    short int: "short int",         unsigned short int: "unsigned short int",     \
          int: "int",                     unsigned int: "unsigned int",           \
     long int: "long int",           unsigned long int: "unsigned long int",      \
long long int: "long long int", unsigned long long int: "unsigned long long int", \
        float: "float",                         double: "double",                 \
  long double: "long double",                   char *: "pointer to char",        \
       void *: "pointer to void",                int *: "pointer to int",         \
      default: "other")

int main()
{
    int a=1,b=2;
    float c=3.14159,d=0;
    printf("a type: %s, b type: %s, c type: %s, d type: %s\n",typename(a),typename(b),typename(c),typename(d));
    a=(float)b+(float)c;
    printf("a=b+c, a=%d\n",a);
    printf("type (b+c): %s\n",typename((int)b+(int)c));
    d=(int)b+(int)c;
    printf("d=b+c, d=%f\n",d);
    return 0;
}
運行案例 點擊 "運行案例" 可查看在線運行效果

下面是執行結果。

a type: int, b type: int, c type: float, d type: float
a=b+c, a=5
type (b+c): int
d=b+c, d=5.000000

通過顯式類型轉換,我們可以控制在計算過程中的數據類型。之前自動轉換為 float 類型的數據,在我們顯式指定為 int 類型后,計算過程中就會按照 int 類型來進行計算。

3. 小結

對于隱式類型轉換。其實變化的原因主要是因為計算的數值為了匹配計算精度而進行的,一般情況下都是較低精度的變量類型會轉變為較高精度的變量類型。

而顯式類型轉換則是我們主動控制了類型的精度,可以拋去我們不需要的高的精度。同時,由于指定了類型,在轉換過程中不會產生歧義。

Tips: 請注意,這里在類型轉換的過程中不會自動進行四舍五入等操作,因此如果使用不當會造成數據的精度丟失。