同樣是看過C Programming: A Modern Approach的筆記整理。一樣,寫的時候手上沒書,請自行斟酌,盡信書不如無書,更何況是組裝工亂寫的東西呢。
一般來說,變數型態可以強制轉換,這學過C 語言應該都知道。不過看了書上才發現不只強制轉換,compiler也會幫你的程式碼加料、做型態轉換。更恐怖的是,沒注意到的話,會發生慘劇。
本文開始之前,先定義專有名詞:
書中提到潛規則型態轉換發生的時機如下
後面兩種大概就是下面這樣的情況吧
long test(int i)
{
i = 0.5f;
return i;
}
書中用下面的方式分類C 語言的潛規則型態轉換規則,分別整理如下,偷懶不講C99了。
這個最簡單,等號左邊用啥型態右邊就得轉成這樣的型態。這也是為何
int i = 11.039;
printf("%d", i);
結果會是11的原因。
一樣這是compiler的術語。此這邊就是一堆的歡樂的型態排列組合,C99還有_Complex
和_Bool
參戰。
一樣先分類
float
-> double
-> long double
unsigned
還是signed
整數依照下面的順序promote:
int
-> unsigned int
-> long int
-> unsigned long int
...#include <stdio.h>
void implicit_conv()
{
int i = -1;
unsigned int j = 100;
if (i < j) {
printf("expected\n");
}
else {
printf("GG\n");
}
}
int main(int argc, char **argv)
{
implicit_conv();
return 0;
}
執行結果如下
$ make implicit
cc implicit.c -o implicit
$ ./implicit
GG
為何會GG呢,因為 i < j
是一個expression,照上面的規矩,expression同時有int
和unsigned int
的話,int
會被promote的unsigned int
,-1
的二進位不知道的人,可能要先搞懂再來學C吧?
如果你擔心程式有類似的問題,可以把gcc
最囉唆的檢查打開,就會噴出錯誤如下
$ make implicit CFLAGS="-Wall -Wextra -Werror"
cc -Wall -Wextra -Werror -c -o implicit.o implicit.c
implicit.c: In function ‘implicit_conv’:
implicit.c:7:11: error: comparison between signed and unsigned integer expressions [-Werror=sign-compare]
if (i < j) {
^
implicit.c: In function ‘main’:
implicit.c:15:14: error: unused parameter ‘argc’ [-Werror=unused-parameter]
int main(int argc, char **argv)
^
implicit.c:15:27: error: unused parameter ‘argv’ [-Werror=unused-parameter]
int main(int argc, char **argv)
^
cc1: all warnings being treated as errors
make: *** [implicit.o] Error 1
你可能會問,那有小數點的型態和整數型態亂戰會怎樣呢?自己估狗或看書吧。
由於這些潛規則,在轉換型態的時候,可以看到這樣的statement。
double whatsoever;
whatsoever = (double) 10 / 3;
為什麼3
不用型態轉換呢?你必須要比對C語言的Operator precedence,也就是運算元處理順序。可以知道C 語法會處理順序如下
10
cast成double
型態3
也會被promote成doule
10 / 3
=
左邊的變數在C語言中有小數點的常數預設型態可是double
唷。所以你如果有float
最好使用下面的方式轉換型態。至於為什麼會規定是double
呢?書中有講八卦,就不破梗了。
float whatsoever = 3.14f;