在 Linux 中操作 u64 类型
我们如何在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)
任何建议表示赞赏。非常感谢!
How can we manipulate the 32 bits high order and 32 bits low order of u64 type in Linux kernel. I tried this one, but the compiler reported a lot of warnings.
#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)
Any suggestions are appreciated. Thank a lot!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我怀疑,首先,您将需要对那些大的十六进制数字进行限定符,类似于:
未修饰的整数常量属于
int
类型,这可能不足以保持给定的值。除此之外,您应该发布您收到的警告,这样我们就不必玩心灵调试游戏:-)
还有一件事可能有问题是
v << 32
表示 32 位v
。我可能会选择类似的东西:这将确保在进行任何位移之前一切都是正确的类型。请记住,这是未经测试的,您必须确认正确的行为。
但是,当然,我错过了尼古拉斯·奈特在评论中提出的最明显的解决方案。完全摆脱宏。这是由函数处理得更好的事情(如果你愿意的话可以标记为内联,但我很少发现这是必要的,因为
gcc
反正优化得非常好)。这样,编译器就可以强制数据类型,并且您不会遇到使用
#define SQR(x) ((x)*(x))
和等宏总是遇到的问题i = SQR(j++)。
I suspect, for a start, that you're going to need qualifiers on those big honkin' hex numbers, something along the lines of:
Unadorned integer constants are of the
int
type and that's probably not enough to hold the given values.Other than that, you should post the warnings you're getting so we don't have to play the Psychic Debugging game :-)
And one other thing that may be problematic is
v << 32
for a 32-bitv
. I'd probably opt for something like:This would make sure that everything is of the correct type before doing any bit shifting. Keep in mind that's untested, you'll have to confirm the correct behaviour.
But, of course, I missed the most obvious solution as put forward by Nicholas Knight in a comment. Get rid of the macros altogether. This is something far better handled by functions (marked inline if you wish but I rarely find this necessary since
gcc
optimises things insanely well anyway).This way, the compiler can coerce data types and you don't run into the problems you invariably do with macros like
#define SQR(x) ((x)*(x))
andi = SQR(j++)
.正如其他人已经说过的,正确的 typedef 是
uint64_t
。该类型的常量可以通过预定义宏UINT64_C
获得,例如UINT64_C(1)
可能会产生1ULL
。但实际上我认为你不需要这些。如果您确实有该类型的变量(即固定宽度 64 且无符号),以 32 位移位两次应该总是给出正确的结果。仅具有高位
编译器会将其优化为适合您平台的完美汇编器。 (对于 gcc,使用
-march=native
进行编译,并使用-S
检查汇编器。)要确保这确实是一个
uint64_t
最好的确实像别人说的有功能。然后它会转换为正确的类型,您不必担心。如此小的函数定义属于头文件,因此您必须要么将其声明为
内联
(或静态
,如果你必须),否则你会在链接时遇到“多重定义符号”错误。要在某处声明函数的符号,您必须在一个编译单元中放置一个
extern inline
声明(而不是定义)。As already said by others, the correct typedef is
uint64_t
. Constants of that type can be obtained by the predefined macroUINT64_C
, e.gUINT64_C(1)
will probably result in1ULL
. But actually I don't think you need these.If you really have a variable of that type (i.e with fixed width 64 and unsigned) shifting twice with 32 bit should always give the correct result. To only have the high order bits
The compiler will optimize this to the perfect assembler for your platform. (For gcc, compile with
-march=native
and check the assembler with-S
.)To be sure that this is really an
uint64_t
best is really as others said to have a function. This then converts to the right type(s), and you don't have to worry.Such a small function definition belongs in a header file, so you must either declare it
inline
(orstatic
if you must), otherwise you will encounter "multiply defined symbol" errors at link time.To also have a symbol declared of your function somewhere, you'd have to put an
extern inline
declaration (not definition) in exactly one compilation unit.