C,位移。连续2班

时间:2013-01-30 06:37:27

标签: c

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

2 个答案:

答案 0 :(得分:8)

这两种方法并不完全相同,具体取决于底层数据类型。标准(C11,6.5.7按位移位运算符)表明:

  

如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。

因此,如果要将32位宽整数类型32位向右移位,则会导致未定义的行为。但是,将它移位31位然后另一位 定义良好。

这一点,虽然有人可能这样做的原因,但在这种特殊情况下可能没有实际意义。鉴于您的类型为unsigned long long(保证64位宽度),(x >> 31) >> 1x >> 32之间应该没有区别。

但是,如果某个平台实际上将ext4_fsblk_t定义为32位类型(或者如果它是从允许32位类型(a)的早期实现中继承的话),你会发现自己不得不采用两阶段的转变来保证定义的行为。


(a)ext3ext4之间有一个临时阶段,允许ext3移动到48位,这是一个垫脚石在使用其64位数据类型的ext4的路上。在此之前,8TB是文件系统的实际限制。

可能,虽然我还没有确认,但是在基础数据类型达到64位宽之前,此代码段是该转换的拖尾。

要使用的类型sector_t有条件地定义为u64unsigned long,这可以解释为什么代码首先存在。在将其定义为后者的情况下,可能需要两个阶段的转变。

然而,鉴于ext4已经离开了这个临时阶段,我不确定是否需要进行两阶段转变。最好的办法是提出变更请求,看看它是否被开发人员击落: - )

答案 1 :(得分:4)

我可以想象代码已从ext3复制,其中ext3_fsblk_t被定义为unsigned long(32位)。在这种情况下,paxdiablo的论证是正确的:

  

标准(C11,6.5.7按位移位运算符)表明:

     
    

如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。

  
     

因此,如果将32位整数32位向右移位,则它是未定义的。但是,将它移位31位然后再定位另一位。

对于ext4_fsblk_t定义为unsigned long longlong long依次为guaranteed to be 64 bit,此代码不再有意义。