繁体   English   中英

C,位移。连续2班

[英]C, bit shift . 2 consecutive shifts

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为什么不这样做?

谢谢

编辑:谢谢大家。 发送补丁到ext4 maillist

这两种方法并不完全相同,具体取决于底层数据类型。 标准(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已经离开了这个临时阶段,我不确定是否需要进行两阶段转换。 最好的办法是提出变更请求,看看它是否被开发人员击落:-)

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

标准(C11,6.5.7按位移位运算符)指出:

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

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

对于ext4_fsblk_t ,定义为unsigned long longlong long保证为64位,此代码不再有意义。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM