9
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 邮件列表

4

2 回答 2

8

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

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

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

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

但是,如果某些平台实际上定义ext4_fsblk_t为 32 位类型(或者如果它是从允许 32 位类型(a)的早期实现继承而来),您会发现自己不得不求助于两阶段转换来保证定义的行为。


(a):在和之间有一个过渡阶段ext3ext4它允许移动到 48 位及其范围,这是通往64 位数据类型ext3的垫脚石。ext4在此之前,8TB 是文件系统的实际限制。

尽管我还没有确认,这个代码片段有可能是该转换的遗留物,在基础数据类型达到 64 位宽之前。

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

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

于 2013-01-30T06:42:24.157 回答
4

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

该标准(C11,6.5.7 位移位运算符)规定:

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

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

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

于 2013-01-30T07:00:04.890 回答