在Linux内核中,我发现了以下代码:
static inline loff_t pos_from_hilo(unsigned long high, unsigned long low)
{
#define HALF_LONG_BITS (BITS_PER_LONG / 2)
return (((loff_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low;
}
该代码用于将系统调用参数组合成一个更宽的变量,例如在ia32上,pwritev的偏移量在两个32位寄存器中指定。
在x64上,loff_t和unsigned long都是64位宽。在这种情况下,高变量被忽略,只使用低变量。在ia32上,loff_t为64位宽,unsigned long为32位宽。在这种情况下,将组合两个参数high和low。
我想知道为什么代码要进行两次位移而不是一次。关于这段代码有更多的信息,请参见提交消息和LWN文章:系统调用和64位架构,但没有解释双重位移的原因。
return low;
呢? - Bob__BITS_PER_LONG
是unsigned long
的宽度,但loff_t
可能更宽。我相信这个想法是为了编写代码,以便在loff_t
比unsigned long
更宽时将high
和low
打包到返回值中,并且如果它们具有相同的宽度,则仅返回low
。 - Nate Eldredgetypedef
,loff_t
最终会成为一个long long
,因此用两个unsigned long
填充它是否会导致 UB? - Bob__-fno-strict-overflow
构建的,因此有符号整数溢出不是UB,而是保证会环绕。所以我认为一切都很好。在一个unsigned long
为32位且loff_t
为64位的系统上,您将high
和low
打包到返回值中,如果high
太大,那么发生的所有情况就是返回值为负数(可能在其他地方进行检查)。如果unsigned long
和loff_t
都是64位,则(((loff_t)high << HALF_LONG_BITS) << HALF_LONG_BITS)
保证计算结果为0,然后我们只返回low
。 - Nate Eldredge