2016年4月22日 星期五

C 語言的 usual arithmetic conversion

程式在下面的文章哦!

ptt [問題] 十三誡之七的疑問》有一個這樣的問題。

a5.c
 1 #include <stdio.h>
 2 
 3 int main(int argc, char *argv[])
 4 {
 5   unsigned int a = 0;
 6   for(int i = 9 ; i >= a ; i--) 
 7   {  
 8     printf("i: %x\n", i);
 9   }
10     
11   return 0;
12 }

a5.c 執行結果是
i: 9
i: 8
i: 7
i: 6
i: 5
i: 4
i: 3
i: 2
i: 1
i: 0
i: ffffffff
i: fffffffe
i: fffffffd
i: fffffffc
i: fffffffb
i: fffffffa
i: fffffff9
i: fffffff8
i: fffffff7
i: fffffff6
i: fffffff5
i: fffffff4
...
...
... 

i 被當成 unsigned int 看待了, 這是怎麼回事?

tinlans Re: [問題] 十三誡之七的疑問》回覆的很詳細, 不過你可能被 c spec 的英文和複雜的規定搞得更亂了 (是少我是這樣), 《inux c 編程 一站式學習》 3.2. Usual Arithmetic Conversion 有簡單一點的說明。

a5.c 符合這點:
否则,如果一边是无符号数另一边是有符号数,无符号数的Rank不低于有符号数的Rank,则把有符号数转成另一边的无符号类型。例如unsigned long和int做算术运算时都转成unsigned long,unsigned long和long做算术运算时也都转成unsigned long。

其實就是 fig 1 的中文翻譯, 英文果然不是很好懂。

fig 1 n1570 c11 spec draft sual arithmetic conversion
寄件者 ??

所以 L6 int i 被轉成 unsigned int i 之後才和 a 做比較; i >= a 是以 unsigned int 在做比較, unsigned int 自然沒有小於零的數, 所以條件便一直成立。

這並不是 Integer Promotion, 而是 usual arithmetic conversion, 別搞錯了。

可见有符号和无符号整数的转换规则是十分复杂的,虽然这是有明确规定的,不属于阴暗角落,但为了程序的可读性不应该依赖这些规则来写代码。我讲这些规则,不是为了让你用,而是为了让你了解有符号数和无符号数混用会非常麻烦,从而避免触及这些规则,并且在程序出错时记得往这上面找原因。所以这些规则不需要牢记,但要知道有这么回事,以便在用到的时候能找到我书上的这一段。

感謝作者宋劲杉的苦口婆心。

如果你對《inux c 編程 一站式學習》這本書寫的有懷疑, 又看不懂 c spec, the c programming language 繁體中文版 A6.5 也介紹了 usual arithmetic conversions 的規則, 寫的不是很詳細, 不過對照程式應該可以看懂為什麼是符合該轉換規則。

fig 2 一樣在說明這件事。
fig 2 C语言程序设计现代方法第2版

C11: ISO/IEC 9899:2011 specification 似乎沒有想像中的恐怖, 大概 180 頁左右, 後面是標準程式庫。

ref:
C 語言的潛規則型態轉換

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。