轉自:http://www.cnblogs.com/hfyinsdu/p/4600052.html
參考地址:
http://blog.csdn.net/jk110333/article/details/8177285
http://blog.chinaunix.net/uid-23629988-id-3477143.html
補碼的說明:
http://baike.baidu.com/link?url=qz8yHnVCqqKWguIDLOfcRZDBfLy4h1ekzspS7Rkznu8RdvMYm0QnK_vhBTHP_SSQRzV--lhiGS7lF32fB4xC5q
說明:
計算機位數限制,能表示的數值范圍也是有限的;比如129在8位的計算機中,表示為1000 0001,按有符號數讀取的話就是-127,無符號讀取就是129.
所以在判斷結果是否小於0的時候,應該看存儲的二進制的最高位是否為1.
比如127-(-3)=130,雖然看起來是個正數,但是在8位計算機中,以有符號數讀取的話就是負數,因為130存儲為1000 0010.
Linux內核為了解決jiffies的回繞問題,提供了現成的宏,用於判斷時間的先后。今天就以time_after為例,看看它為什么可以應對jiffies的回繞問題。
/*
* These inlines deal with timer wrapping correctly. You are
* strongly encouraged to use them
* 1. Because people otherwise forget
* 2. Because if the timer wrap changes in future you won't have to
* alter your driver code.
*
* time_after(a,b) returns true if the time a is after time b.
*
* Do this with "<0" and ">=0" to only test the sign of the result. A
* good compiler would generate better code (and a really good compiler
* wouldn't care). Gcc is currently neither.
*/
#define time_after(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)(b) - (long)(a) < 0))
這個宏定義很簡單,可以忽略typecheck,其就是用於檢查參數的類型是否正確。如這里就是用於判斷a和b是否為unsigned long類型。
最關鍵的就是((long)(b) - (long)(a) < 0)。
在理想的情況下,時間是可以不停增長的,后來的時間值一定比前面的值大。所以b-a一定小於0。然后計算機的世界不是一個理想的世界,
所有的值都有其位數限制的。在32位平台上,long的位數為32位。按照二進制補碼的表示方式,從0到0x7fffffff的區間,值是逐漸遞增的。
從0x80000000到0xFFFFFFFF這個區間,值是逐漸縮小的。
這就有4中情況:
1. a和b都在0到0x7FFFFFFF之間:
a若在b之后發生,則a的值大於b。那么(long)b-(long)a<0。
2. a和b都在0x80000000到0xFFFFFFFF之間:
a若在b之后發生,b為較大的負數,a為較小的負數,那么(long)b-(long)a<0。
3. b在0到0x7FFFFFFF之間,而a在0x80000000到0xFFFFFFFF之間:
a為負數。b-a,相當於b+(-a)。只要a與b之間的絕對差值小於或等於0x80000000,則b+(-a)仍然為負數。
4. b在0x80000000到0xFFFFFFFF之間,而a在0到0x7FFFFFFF之間:
b為負數,b-a等於b+(-a)。同樣在a與b之間的絕對差值小於或等於0x80000000,則b+(-a)仍然為負數。
總結這四種情況,在a與b的絕對值相差不到0x80000000時,這個宏是正確的。而在利用jiffies作為時間度量和比較單位時,時間差並不會太大。
所以這個time_after可以有效的避免jiffies回繞問題。