C語言類型轉換知多少?

C語言類型轉換知多少?

 

學C的都知道類型轉換,可是,到底哪些類型轉換是安全的,那些是有危險的?雖然類型統一規劃好是好的程序開發的基礎。但是有些時候避免不了類型轉換的時候,這時候我們需要:

1.      瞭解哪些類型轉換有危險(危險的都是顯式類型轉換?)。

2.      瞭解那些轉換會增加代碼量

3.      如何通過顯式的轉換來減少轉換次數,提高效率

 

類型轉換的方式:

 

短的轉長的

等長的之間

長的轉短的

有符號轉無符號

符號擴展到長的

負數值變含義了

存儲的二進制不變

負數值變含義了

截斷

無符號轉有符號

值不變

大於負數範圍的值變負

截斷

有符號之間

值不變

N/A

截斷

無符號之間

值不變

N/A

截斷

 

1.      double 和整數之間的轉換是直接將小數點後截掉進行轉換,反之,將整數賦值給浮點數的時候,受浮點數表達能力的限制,可能會出現整數部分不完全一樣的情況,這些轉換都需要代碼實現

2.      無論短轉長,還是長轉短,這些轉換都需要代碼實現

 

測試當中,還發現有這個現象:

short a =-100;

unsignedshort b;

 

printf("a=%d\n",a);

printf("a=0x%x\n",a);

b =a;

printf("b=%d\n",b);

printf("b=0x%x\n",b);

 

結果如下:

 

a=-100

a=0xffffff9c

b=65436

b=0xff9c

 

爲什麼a和b的十六進制數打印的不一樣呢?我們看看真正是怎麼處理的:

movw $-100,-2(%rbp)         // a = -100;

movswl    -2(%rbp),%eax     // 準備參數,因爲類型是short,所以做一次隱式轉換,相當於(int)a; 由於是有符號數,所以符號擴展了。

movl %eax,%esi

movl $.LC0,%edi

movl $0,%eax

call printf                  // printf("a=%d\n",(int)a);

movswl    -2(%rbp),%eax

movl %eax,%esi

movl $.LC1,%edi

movl $0,%eax

call printf

movzwl    -2(%rbp),%eax     // 寄存器eax = a; 這裏無論怎麼擴展,下一步取得都只是低32位,所以不會有任何影響。

movw %ax,-4(%rbp)      // b = 寄存器ax(32);

movzwl    -4(%rbp),%eax     // 準備參數,因爲類型是short,所以做一次隱式轉換,相當於(unsigned int)a;

movl %eax,%esi

movl $.LC2,%edi

movl $0,%eax

call printf                  //printf("b=%d\n", (unsigned int)b);

movzwl    -4(%rbp),%eax

movl %eax,%esi

movl $.LC3,%edi

movl $0,%eax

call printf

 

從上面的代碼可以看出,確實printf的輸入參數,小於int的類型是要轉換爲相應的int,然後調用printf進行打印的,這也是C語言函數處理入參的默認行爲。

 

隱式轉換規則:

就是不需要明確指定,編譯器會生成相關的代碼進行轉換:

 

1.      關於表達式運算

首先:不同類型數運算的時候,先要轉換爲相同的,轉換規則是表達能力小的轉換爲表達能力大的,即:短的轉換爲長的。

 

其次:整形計算的最小單位是int,如果是小於int的數字,先要轉換爲int。浮點數計算的單位都是double,所以所有的參與浮點運算的任何一方只要是浮點數,大家都會轉換爲double進行運算。這麼做的原因是:保證精度。

 

2.      關於賦值

賦值是強制按照左邊的類型進行轉換,有可能是顯式的截斷,參見上表。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章