static inline void ext4_ext_store_pblock(struct ext4_extent *ex,
ext4_fsblk_t pb)
{
ex->ee_start_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff));
ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) &
0xffff);
}
此代码来自linux内核。 见最后一行。它确实是pb>> 31然后>> 1 这与pb>>相同32 为什么不这样做?
谢谢
EDITED: 谢谢你们。发送补丁到ext4 maillist
答案 0 :(得分:8)
这两种方法并不完全相同,具体取决于底层数据类型。标准(C11,6.5.7按位移位运算符)表明:
如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。
因此,如果要将32位宽整数类型32位向右移位,则会导致未定义的行为。但是,将它移位31位然后另一位 定义良好。
这一点,虽然有人可能这样做的原因,但在这种特殊情况下可能没有实际意义。鉴于您的类型为unsigned long long
(保证64位宽度),(x >> 31) >> 1
和x >> 32
之间应该没有区别。
但是,如果某个平台实际上将ext4_fsblk_t
定义为32位类型(或者如果它是从允许32位类型(a)的早期实现中继承的话),你会发现自己不得不采用两阶段的转变来保证定义的行为。
(a):ext3
和ext4
之间有一个临时阶段,允许ext3
移动到48位,这是一个垫脚石在使用其64位数据类型的ext4
的路上。在此之前,8TB是文件系统的实际限制。
可能,虽然我还没有确认,但是在基础数据类型达到64位宽之前,此代码段是该转换的拖尾。
要使用的类型sector_t
有条件地定义为u64
或unsigned long
,这可以解释为什么代码首先存在。在将其定义为后者的情况下,可能需要两个阶段的转变。
然而,鉴于ext4
已经离开了这个临时阶段,我不确定是否需要进行两阶段转变。最好的办法是提出变更请求,看看它是否被开发人员击落: - )
答案 1 :(得分:4)
我可以想象代码已从ext3复制,其中ext3_fsblk_t被定义为unsigned long
(32位)。在这种情况下,paxdiablo的论证是正确的:
标准(C11,6.5.7按位移位运算符)表明:
如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。
因此,如果将32位整数32位向右移位,则它是未定义的。但是,将它移位31位然后再定位另一位。
对于ext4_fsblk_t定义为unsigned long long
而long long
依次为guaranteed to be 64 bit,此代码不再有意义。