Logo
Section 1 / 8

按位取反

详细了解按位取反。

导入

按位取反

详细了解按位取反。

位运算 会单独处理数字的每一位。我们在编程时经常使用它们。下面我们详细探讨它们的工作原理。

位取反

首先,我们来看最简单的位运算:取反。它也被称为位非(bitwise NOT)。在 Bash 中,使用波浪号符号(~)表示该操作。

进行位取反时,我们会交换整数每一位的值。也就是说,将每个 1 变为 0,每个 0 变为 1。

以下是以数字 5 为例进行位非运算的示例:

15 = 101 2~5 = 010

从数学角度看,位取反是一个简单操作。但在编程中使用时需要注意一些陷阱。我们需要牢记两点:

  • 数字占用多少字节?
  • 数字在内存中的表示方式是什么?

假设一个两字节变量存储数字 5,那么它在内存中的表示如下:

100000000 00000101

对该变量执行位取反后,结果为:

111111111 11111010

这些位代表什么?如果将其存储为无符号整型变量,则得到数值 65530。如果变量是有符号整型,则等于 -6。我们可以通过将补码表示转换为十进制来验证这一点。

Bash 的不同内置命令和运算符对整数的表示方式不同。例如,echo 始终以有符号整数形式输出数字。而 printf 命令允许我们选择有符号或无符号整数。

Bash 语言本身没有类型。所有标量变量都以字符串形式存储。在参与算术表达式之前,Bash 会将字符串转换为整数。整数的解释方式(有符号或无符号)取决于上下文。

Bash 中允许的最大和最小整数

Bash 为每个整数分配 64 位内存空间,无论其符号如何。下表展示了 Bash 中允许的最大和最小整数。

整数类型十六进制十进制
最大正有符号整数7FFFFFFFFFFFFFFF9223372036854775807
最小负有符号整数8000000000000000-9223372036854775808
最大无符号整数FFFFFFFFFFFFFFFF18446744073709551615

以下示例展示了 Bash 在 (( 运算符、echo 和 printf 内置命令中如何解释整数:

1$ echo $((16#FFFFFFFFFFFFFFFF)) 2-1 3 4$ printf "%llu\n" $((16#FFFFFFFFFFFFFFFF)) 518446744073709551615 6 7$ if ((18446744073709551615 == 16#FFFFFFFFFFFFFFFF)); then echo "ok"; fi 8ok 9 10$ if ((-1 == 16#FFFFFFFFFFFFFFFF)); then echo "ok"; fi 11ok 12 13$ if ((18446744073709551615 == -1)); then echo "ok"; fi 14ok

上述最后一个比较示例(18446744073709551615 与 -1)证实了 Bash 在内存中以相同方式存储有符号和无符号整数,但根据上下文进行不同的解释。

回到数字 5 的位取反运算。Bash 返回的结果是十六进制的 0xFFFFFFFFFFFFFFFFFA。我们可以将其以正数或负数形式打印出来,如下所示:

1$ echo $((~5)) 2-6 3 4$ printf "%llu\n" $((~5)) 518446744073709551610

在 Bash 中,数值 18446744073709551610 和 -6 是相等的。这是因为它们在内存中的所有位都完全相同。

算术表达式与运算

练习:按位取反