在Linux中操作u64类型

时间:2011-04-19 08:26:46

标签: c linux unix 64-bit

如何在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)

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

2 个答案:

答案 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声明(不是定义)。