2011-04-19 46 views
2

在Linux內核中,我們如何操作u64類型的32位高階和32位低階。我試過這個,但編譯器報告了很多警告。在Linux中操縱u64類型

#define HI_BYTES(_a) (_a & 0xffffffff00000000) 
#define LO_BYTES(_a) (_a & 0x00000000ffffffff) 
/* _v is 32 bit value */ 
#define HI_BYTES_SET(_a, _v) do {_a = (_a & 0x00000000ffffffff) | (_v << 32)} while (0) 
#define LO_BYTES_SET(_a, _v) do {_a = (_a & 0xffffffff00000000) | (_v)} while (0) 

任何建議表示讚賞。非常感謝!

+1

警告說什麼? – 2011-04-19 08:31:28

+0

u64?也許你的意思是uint64_t?你真的需要混淆宏而不是粘在一個小的內聯函數中,讓編譯器完成它的工作嗎? – 2011-04-19 08:33:58

+1

它抱怨移位量和恆定值0xffffffff00000000太大。感謝大家花時間回答: – 2011-04-19 14:52:37

回答

5

我懷疑,一開始,你會需要對那些大honkin預選賽十六進制數字,沿着線的東西:

0xffffffff00000000ULL 

樸實的整型常量是int型的,這就是可能不足以保持給定的值。

除此之外,你應該你得到後的警告,所以我們沒有打心理調試遊戲:-)


,另一種可能是另一件事問題是v << 32爲32位v。我可能會選擇類似:

#define HI_BYTES(_a) (_a & 0xffffffff00000000ULL) 
#define LO_BYTES(_a) (_a & 0x00000000ffffffffULL) 
#define HI_BYTES_SET(_a, _v)\ 
    do {\ 
     u64 _xyzzy = _v;\ 
     _a = (_xyzzy << 32) | LO_BYTES(_a)\ 
    } while (0) 
#define LO_BYTES_SET(_a, _v)\ 
    do {\ 
     u64 _xyzzy = _v;\ 
     _a = HI_BYTES(_a) | (_xyzzy)\ 
    } while (0) 

這將確保一切是正確的類型做任何位移位之前。請記住,這是未經測試的,您必須確認正確的行爲。


但是,當然,我錯過了Nicholas Knight在評論中提出的最明顯的解決方案。完全擺脫宏。這可以通過函數更好地處理(如果你願意的話可以內聯標記,但我很少發現這個必要,因爲無論如何,gcc都能很好地優化事物)。

這樣,編譯器可以強制數據類型,並且不會遇到像#define SQR(x) ((x)*(x))i = SQR(j++)這樣的宏常常會遇到的問題。

2

正如其他人所說的,正確的typedef是uint64_t。該類型的常量可以通過預定義的宏UINT64_C獲得,例如UINT64_C(1)可能會導致1ULL。但實際上我不認爲你需要這些。

如果你真的有一個這種類型的變量(即固定寬度64和無符號)兩次移動32位應始終給出正確的結果。只需要高位

((a >> 32) << 32) 

編譯器會優化這個到你的平臺的完美彙編器。 (對於gcc,使用-march=native進行編譯,並使用-S檢查彙編程序。)

要確定這真的是uint64_t最好的確如其他人所說的那樣具有函數。然後這轉換成正確的類型,你不必擔心。

這種小的函數定義屬於在頭文件中,所以你必須要麼聲明它inline(或static如果必須),否則會遇到在鏈接時「乘定義的符號」錯誤。

若要在某處聲明符號,則必須在一個編譯單元中放入extern inline聲明(而非定義)。

+0

感謝Jens Gustedt:D – 2011-04-19 14:51:32

+0

'u64'實際上是Linux內核的有效類型 - 並非所有的編譯器都可以提供'uint64_t'類型。 – paxdiablo 2011-04-20 03:19:12