You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于(x | y) - y等效性及内核中(SPINLOCK_SHARED|1)-1作用的疑问

嘿,这两个问题问到点子上了,都是底层编程里容易忽略的细节,我来给你一步步拆解清楚:

疑问1:为什么(x | y) - y不能直接简化为x或x | 0?

核心原因是当x和y的二进制位存在重叠时,位或操作会改变重叠位的状态,导致减法后的结果和原x不一致。咱们用具体的二进制例子来说明:

  • 情况1:x和y无重叠位(比如x=0b0011,y=0b1000)
    x | y = 0b1011,减去y(0b1000)后得到0b0011,确实等于x。这也是容易让人误以为可以简化的场景,但这只是特例。
  • 情况2:x和y有重叠位(比如x=0b1010,y=0b0110)
    x | y = 0b1110,减去y(0b0110)后得到0b1000,而原x是0b1010,显然结果不等于x。

本质上,(x | y) - y等价于x & (~y)——也就是只保留x中那些没有被y的二进制位覆盖的部分。只有当x和y的位完全不重叠时,x & (~y)才等于x,否则结果会丢失x中与y重叠的位。而x | 0就是x本身,和这个表达式的逻辑完全不是一回事。

疑问2:为什么内核代码里要用value == (SPINLOCK_SHARED | 1) - 1而不是直接写value == SPINLOCK_SHARED?

先明确前提:SPINLOCK_SHARED是0x80000000,也就是32位有符号整数的最小值(-2147483648)。这种写法的核心目的是规避C语言中常量类型解析和溢出行为的坑,具体来说:

  1. 直接使用0x80000000的类型问题
    在C语言中,整数常量的默认类型是int,但0x80000000超出了32位有符号int的正范围(最大是0x7FFFFFFF)。有些编译器会把它解析为unsigned int类型。如果value是一个有符号int变量,直接比较value == SPINLOCK_SHARED会触发有符号与无符号的隐式转换,把value转换成无符号数,虽然结果可能对,但这是依赖编译器行为的隐患,移植性差。

  2. (SPINLOCK_SHARED | 1) - 1的作用

    • 第一步SPINLOCK_SHARED | 1得到0x80000001,这个值属于32位有符号int的合法范围(对应-2147483647),编译器会把它解析为有符号int。
    • 第二步减1,得到0x80000000,这时候这个结果的类型仍然是有符号int,也就是标准的32位有符号整数最小值。

这样一来,整个表达式的类型和value(有符号int)完全一致,避免了隐式类型转换带来的不确定性,保证了在不同编译器和平台上的行为一致。这种写法是Linux内核里常见的“类型安全”技巧,用来绕过C语言常量类型规则的模糊地带。


内容的提问来源于stack exchange,提问作者RaGa__M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:16:54