C、 位移位。连续2班

C、 位移位。连续2班,c,C,这段代码来自linux内核。 见最后一行。它会执行pb>>31然后>>1 这与pb>>32相同吗 为什么不这样做呢 多谢各位 编辑: 谢谢大家。将补丁发送到ext4邮件列表这两种方法并不完全相同,具体取决于底层数据类型。标准(C11,6.5.7位移位运算符)规定: 如果右操作数的值为负或大于或等于提升后的左操作数的宽度,则行为未定义 因此,如果将32位宽的整数类型32位右移,将导致未定义的行为。然而,将其移位31位,然后再移位另一位是定义良好的 这一点虽然是某些人可能会这样做的原因,但在这一特定

这段代码来自linux内核。 见最后一行。它会执行pb>>31然后>>1 这与pb>>32相同吗 为什么不这样做呢

多谢各位

编辑:
谢谢大家。将补丁发送到ext4邮件列表这两种方法并不完全相同,具体取决于底层数据类型。标准(C11,6.5.7位移位运算符)规定:

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

因此,如果将32位宽的整数类型32位右移,将导致未定义的行为。然而,将其移位31位,然后再移位另一位是定义良好的

这一点虽然是某些人可能会这样做的原因,但在这一特定案例中可能没有实际意义。如果您的类型是
无符号长
(保证64位宽度),那么
(x>>31)>>1
x>>32
之间应该没有区别

但是,如果某个平台实际将
ext4\u fsblk\u t
定义为32位类型(或者如果它是从允许32位类型(a)的早期实现中继承过来的),您将发现自己必须求助于两阶段转换来保证定义的行为


(a) :在
ext3
ext4
之间有一个过渡阶段,允许
ext3
使用其扩展数据块移动到48位,这是使用其64位数据类型实现
ext4
的踏脚石。在此之前,8TB是文件系统的实际限制

虽然我还没有确认,但在底层数据类型扩展到64位之前,这段代码片段可能是该转换的遗留问题

即将使用的类型,
sector\u t
,被有条件地定义为
u64
无符号long
,这可能解释了代码首先存在的原因。在定义为后者的情况下,可能需要两阶段转换


然而,考虑到
ext4
已经将这个过渡阶段抛在了脑后,我不确定是否还需要两个阶段的转换。最好的办法是提出一个更改请求,看看它是否被开发人员否决:-)

我可以想象代码是从ext3复制的,ext3的定义是
无符号长(
)(32位)。在这种情况下,paxdiablo的论点是正确的:

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

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

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


For被定义为无符号long和
long
反过来,此代码不再有意义。

什么数据类型是
pb
?下面,什么是
ext4\u fsblk\u t
?typedef unsigned long ext4\u fsblk\t
pb
保证至少为64位。因此,移位32将不会调用未定义的行为。如果有什么问题的话,我不得不猜测,编写该代码的人可能有点偏执,不确定标准的细节。@Mystical,或者,也许,代码的一部分以前是32位的。@AndersLind如果邮件列表中出现讨论,您也可以在这里更新。我刚刚在档案中找到了你的帖子,是为那些有兴趣查找自己的人准备的:嗯,移位31位(对于有符号的32位整数)已经有了将符号位复制到所有位的效果。所以我看不出移位32的目的。@Mystical:它是无符号的,所以应该是逻辑移位。我猜long-long可能是32位,但这是为了防止在这种情况下出现未定义的行为。@Mystical,是的,这可能适用于有符号整数,但这里不一定是这样。@GuySirton哦,现在我看到了注释。这是一个
无符号的long
。“这保证至少是64位。”paxdiablo嗯,至少有研究会指出这一点。由于ext4定义了64位blocknumbers(),因此ext4_fsblk_t不太可能被定义为32位类型,因为这会破坏ext4格式。不过,对于ext2和ext3,有一个配置选项可以使用ext4驱动程序,但不确定会有什么影响have@technosaurus因为这个选项显然不会改变ext4_fsblk_的类型,所以我不认为有什么影响。但是+1指出了这一点。非常感谢。
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);
}