在Linux中操作u64types

在Linux内核中如何操作u64型的32位高位和32位低位。 我试过这个,但编译器报告了很多警告。

#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) 

任何build议表示赞赏。 非常感谢!

我怀疑,一开始,你将需要对那些大的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) 

在做任何位移之前,这将确保一切都是正确的。 请记住,这是未经测试的,你必须确认正确的行为。


但是,当然,我错过了尼古拉斯·奈特提出的最明显的解决方案。 完全摆脱宏。 这是更好的处理功能(如果你希望内联标记,但我很少发现这一点,因为无论如何gcc优化疯狂的事情)。

通过这种方式,编译器可以强制数据类型,而且不会遇到像#define SQR(x) ((x)*(x))i = SQR(j++)这样的宏#define SQR(x) ((x)*(x))会遇到的问题。

正如其他人所说的,正确的typedef是uint64_t 。 该类型的常量可以通过预定义的宏UINT64_C ,例如UINT64_C(1)可能会导致1ULL 。 但实际上我不认为你需要这些。

如果你真的有一个这样的类型的变量(即固定宽度64和无符号)两次移动32位应始终给出正确的结果。 只有高位

 ((a >> 32) << 32) 

编译器将优化这个到你的平台的完美汇编。 (对于gcc,使用-march=native编译,并使用-S检查汇编程序。)

可以肯定的是,这真的是最好的,就像别人所说的那样。 然后这转换成正确的类型,你不必担心。

这样一个小的函数定义属于头文件,所以你必须声明它是inline (如果你必须是static ),否则你会在链接时遇到“多重定义的符号”错误。

为了在你的函数中也有一个符号声明,你必须在一个编译单元中放置一个extern inline声明(而不是定义)。