[英]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) >> 1
和x >> 32
之间应该没有区别。
但是,如果某个平台实际上将ext4_fsblk_t
定义为32位类型(或者如果它是从允许32位类型(a)的早期实现中继承),那么您将发现自己不得不求助于两阶段转换到保证定义的行为。
(a) :在ext3
和ext4
之间有一个临时阶段,它允许ext3
以其范围移动到48位,这是通过其64位数据类型到ext4
的途中的垫脚石。 在此之前,8TB是文件系统的实际限制。
虽然我还没有确认,但是在底层数据类型达到64位宽之前,这个代码片段可能是该转换的一个宿醉。
将要使用的类型sector_t
有条件地定义为u64
或unsigned long
,这可以解释为什么代码首先存在。 在将其定义为后者的情况下,可能需要两阶段的转变。
但是,鉴于ext4
已经离开了这个临时阶段,我不确定是否需要进行两阶段转换。 最好的办法是提出变更请求,看看它是否被开发人员击落:-)
我可以想象代码已从ext3复制,其中ext3_fsblk_t被定义为unsigned long
(32位)。 在这种情况下,paxdiablo的论证是正确的:
标准(C11,6.5.7按位移位运算符)指出:
如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。
因此,如果将32位整数32位向右移位,则它是未定义的。 但是,定义了31位然后另一位的移位。
对于ext4_fsblk_t ,定义为unsigned long long
, long long
又保证为64位,此代码不再有意义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.