& 在 C 语言中是一个位运算符,称为按位与(Bitwise AND),它的核心功能是对两个整数的二进制表示形式,逐位进行“与”运算。

核心概念:按位与
“与”运算的规则是:对于两个二进制位,只有当两者都为 1 时,结果的对应位才为 1,否则,结果为 0。
可以总结为:
1 & 1 = 11 & 0 = 00 & 1 = 00 & 0 = 0
运算过程:
当对两个整数进行 & 运算时,C 编译器会将它们转换成二进制形式,然后对齐每一位(从最低位到最高位),逐对应用上述规则,最后得到一个新的二进制数,这个数就是运算结果。
运算示例
让我们通过一个具体的例子来理解,假设我们要计算 12 & 10。

第一步:将十进制数转换为二进制
12的二进制是110010的二进制是1010
为了方便对齐,我们通常写成相同位数的形式:
12: 1100
10: 1010
第二步:逐位进行“与”运算 我们从右到左(从最低位到最高位)逐位计算:
- 第 0 位 (最右边):
0 & 0 = 0 - 第 1 位:
0 & 1 = 0 - 第 2 位:
1 & 0 = 0 - 第 3 位:
1 & 1 = 1
组合起来,得到的结果二进制是 1000。
第三步:将结果二进制转换回十进制
1000(二进制) =1 * 2³ + 0 * 2² + 0 * 2¹ + 0 * 2⁰=8 + 0 + 0 + 0=8
12 & 10 的结果是 8。
& 的主要用途
& 运算符在 C 语言中有几个非常重要的用途,远不止简单的数值计算。
位屏蔽
这是 & 最常见的用途,它的作用是从一个数的二进制位中“提取”或“保留”我们想要的某些位,同时忽略(置为0)其他位。
原理:
- 要保留的位,与
1进行&运算。x & 1的结果永远是x本身的值。 - 要屏蔽(置为0)的位,与
0进行&运算。x & 0的结果永远是0。
示例:
假设我们有一个 8 位的无符号数 char a = 173,其二进制为 10101101。
我们只想知道它的低4位是什么。
我们可以构造一个“掩码”(Mask)0x0F(十六进制),它的二进制是 00001111。
#include <stdio.h>
int main() {
unsigned char a = 173; // 二进制: 10101101
unsigned char mask = 0x0F; // 二进制: 00001111
unsigned char result = a & mask;
printf("原始值 a: %u (二进制: 10101101)\n", a);
printf("掩码 mask: %u (二进制: 00001111)\n", mask);
printf("结果 a & mask: %u (二进制: 00001101)\n", result);
return 0;
}
运算过程:
10101101 (a)
& 00001111 (mask)
-----------
00001101 (result)
结果 00001101 13,成功提取了低4位。
检查某一位是否为 1
这是位屏蔽的一个特例,如果我们想知道一个数的特定位(比如第2位)是否为 1,我们可以用 1 左移到该位置,然后与原数进行 & 运算。
原理:
- 如果结果的值为
0,说明该位是0。 - 如果结果的值不为
0(等于那个移位后的值),说明该位是1。
示例:
检查 a 的第 2 位(从0开始计数)是否为 1。
#include <stdio.h>
int main() {
unsigned char a = 12; // 二进制: 1100
// 我们想检查第2位 (值为 4, 即 1 << 2)
unsigned char bit_to_check = 1 << 2; // 结果是 4 (二进制 0100)
if ((a & bit_to_check) != 0) {
printf("第2位是 1\n");
} else {
printf("第2位是 0\n");
}
unsigned char b = 13; // 二进制: 1101
if ((b & bit_to_check) != 0) {
printf("第2位是 1\n");
} else {
printf("第2位是 0\n");
}
return 0;
}
对于 a = 12 (1100),1100 & 0100 = 0100 (不为0),所以输出 "第2位是 1"。
对于 b = 13 (1101),1101 & 0100 = 0100 (不为0),所以也输出 "第2位是 1"。
取一个变量的内存地址
重要提示: & 还有一个完全不同的用法,作为取地址运算符。
当 & 用在变量名前面时,它不是进行位运算,而是返回该变量在内存中的地址,这个操作对于指针至关重要。
示例:
#include <stdio.h>
int main() {
int num = 100;
int *ptr; // 声明一个整型指针
ptr = # // 将 num 的内存地址赋给 ptr
printf("变量 num 的值: %d\n", num);
printf("变量 num 的地址: %p\n", &num);
printf("指针 ptr 存储的地址: %p\n", ptr);
printf("通过指针 ptr 访问的值: %d\n", *ptr);
return 0;
}
在这个例子中:
&num的意思是“获取num变量的地址”。%p是printf中用于打印地址的格式说明符。
| 用法 | 名称 | 作用 | 示例 |
|---|---|---|---|
a & b |
按位与 (Bitwise AND) | 对两个整数的二进制位逐位进行“与”运算。 | 12 & 10 结果是 8 |
&variable |
取地址 (Address-of) | 获取一个变量在内存中的地址。 | int *p = &x; |
如何区分?
非常简单,看 & 后面跟着什么:
&后面是一个变量名,那么它是取地址运算符。&两边是完整的表达式或变量,那么它是按位与运算符。
理解 & 的这两种截然不同的用法是掌握 C 语言的关键一步。
