如何在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)
任何建议都表示赞赏。非常感谢!
答案 0 :(得分:5)
我怀疑,首先,你需要对那些重要的'hexkin'数字进行限定,这有点像:
0xffffffff00000000ULL
未加修饰的整数常量属于int
类型,这可能不足以容纳给定的值。
除此之外,您应该发布您收到的警告,这样我们就不必玩 Psychic Debugging 游戏了: - )
对于32位v << 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++)
这样的宏所遇到的问题。
答案 1 :(得分: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
声明(不是定义)。