按位运算符

前缀按位运算符

按位运算符类似于逻辑运算符,但按位而不是每布尔值执行。

// bitwise NOT ~: sets all unset bits and unsets all set bits
printf("%'06b", ~0b110110); // 001001

位掩码位掩码运算符

按位 AND &:只有在两个操作数中都设置了一个位

printf("%'06b", 0b110101 & 0b011001); // 010001

按位 OR |:如果在一个或两个操作数中设置了一个位

printf("%'06b", 0b110101 | 0b011001); // 111101

Bitwise XOR ^:如果在一个操作数中设置并且未在另一个操作数中设置,则设置为位,即仅在该操作数中该位处于不同状态时

printf("%'06b", 0b110101 ^ 0b011001); // 101100

位掩码的示例用法

这些运算符可用于操作位掩码。例如:

file_put_contents("file.log", LOCK_EX | FILE_APPEND);

这里,|运算符用于组合两个位掩码。尽管+具有相同的效果,但|强调你正在组合位掩码,而不是添加两个正常的标量整数。

class Foo{
    const OPTION_A = 1;
    const OPTION_B = 2;
    const OPTION_C = 4;
    const OPTION_A = 8;

    private $options = self::OPTION_A | self::OPTION_C;

    public function toggleOption(int $option){
        $this->options ^= $option;
    }

    public function enable(int $option){
        $this->options |= $option; // enable $option regardless of its original state
    }

    public function disable(int $option){
        $this->options &= ~$option; // disable $option regardless of its original state,
                                    // without affecting other bits
    }

    /** returns whether at least one of the options is enabled */
    public function isOneEnabled(int $options) : bool{
        return $this->options & $option !== 0;
        // Use !== rather than >, because 
        // if $options is about a high bit, we may be handling a negative integer
    }

    /** returns whether all of the options are enabled */
    public function areAllEnabled(int $options) : bool{
        return ($this->options & $options) === $options;
        // note the parentheses; beware the operator precedence
    }
}

此示例(假设 $option 始终只包含一位)使用:

  • ^操作符可以方便地切换位掩码。
  • |运算符设置一个忽略其原始状态或其他位的位
  • ~运算符将只有一位设置的整数转换为只有一位未设置的整数
  • 使用 & 的这些属性,& 运算符取消设置:
    • 由于具有设置位的 &= 将不会执行任何操作((1 & 1) === 1(0 & 1) === 0),因此使用仅未设置一位的整数执行 &= 将仅取消设置该位,而不会影响其他位。
    • 未设置位的 &= 将取消该位((1 & 0) === 0(0 & 0) === 0
  • & 运算符与另一个位掩码一起使用将过滤掉该位掩码中未设置的所有其他位。
    • 如果输出设置了任何位,则表示启用了任何一个选项。
    • 如果输出具有位掩码集的所有位,则表示位掩码中的所有选项都已启用。

请记住,这些比较运算符:(< > <= >= == === != !== <> <=>)具有比这些位掩码位掩码运算符更高的优先级:( | ^ &)。由于使用这些比较运算符经常比较逐位结果,因此这是一个常见的陷阱。

位移运算符

按位左移 <<:按给定的步数将所有位向左移位(更重要)并丢弃超过 int 大小的位

<< $x 相当于取消最高的 $x 位并乘以 $xth 的 2 次幂

printf("%'08b", 0b00001011<< 2); // 00101100

assert(PHP_INT_SIZE === 4); // a 32-bit system
printf("%x, %x", 0x5FFFFFFF << 2, 0x1FFFFFFF << 4); // 7FFFFFFC, FFFFFFFF

按位右移 >>:丢弃最低位移并将剩余位向右移位(不太重要)

>> $x 相当于除以 2 的 $x 次幂并丢弃非整数部分

printf("%x", 0xFFFFFFFF >> 3); // 1FFFFFFF

位移的示例用法:

快速除以 16(性能比/= 16 更好)

$x >>= 4;

在 32 位系统上,这将丢弃整数中的所有位,将该值设置为 0.在 64 位系统上,这将取消设置最重要的 32 位并保持最少

$x = $x << 32 >> 32;

显着的 32 位,相当于 $x & 0xFFFFFFFF

注意:在此示例中,使用了 printf("%'06b")。它以 6 位二进制数字输出值。