运算符
算术运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
+ | 加 | 10 + 5 | 15 |
- | 减 | 10 - 5 | 5 |
* | 乘 | 10 * 5 | 50 |
/ | 除 | 10 / 5 | 2 |
% | 取模 (取余) | 10 % 3 | 1 |
++ | 前自增 | a=2; b=++a; | a=3; b=3; |
++ | 后自增 | a=2; b=a++; | a=3; b=2; |
-- | 前自减 | a=2; b=--a; | a=1; b=1; |
-- | 后自减 | a=2; b=a--; | a=1; b=2; |
示例代码:
c
#include <stdio.h>
int main() {
// 2 数相除,要想得到小数的结果,分子分母必须有一个数是小数
double c = 5/2; // 5, 2 个都是整数,只会取整
printf("c1 = %lf\n", c);
c = 5.0/2;
printf("c2 = %lf\n", c);
c = 5/2.0;
printf("c3 = %lf\n", c);
int i = 0;
// 前置++
// 先加后用
int b = ++i;
printf("前置:b = %d, i = %d\n", b, i);
// 后置++
// 先用后加
i = 0;
b = i++;
printf("后置:b = %d, i = %d\n", b, i);
return 0;
}
运行结果:
c1 = 2.000000
c2 = 2.500000
c3 = 2.500000
前置:b = 1, i = 1
后置:b = 0, i = 1
赋值运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
= | 赋值 | a=2; b=3; | a=2; b=3; |
+= | 加等于 | a=0; a+=2;等同于 a = a + 2; | a=2; |
-= | 减等于 | a=5; a-=3;等同于 a = a - 3; | a=2; |
*= | 乘等于 | a=2; a*=2;等同于 a = a * 2; | a=4; |
/= | 除等于 | a=4; a/=2;等同于 a = a / 2; | a=2; |
%= | 模等于 | a=3; a%=2;等同于 a = a % 2; | a=1; |
示例代码:
c
#include <stdio.h>
int main() {
int a = 10;
a += 5;
printf("a = %d\n", a);
return 0;
}
运行结果:
a = 15
比较运算符
C 语言的比较运算中, “真”用数字“1”来表示, “假”用数字“0”来表示。
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
== | 相等于 | 4 == 3 | 0 |
!= | 不等于 | 4 != 3 | 1 |
< | 小于 | 4 < 3 | 0 |
> | 大于 | 4 > 3 | 1 |
<= | 小于等于 | 4 <= 3 | 0 |
>= | 大于等于 | 4 >= 1 | 1 |
示例代码:
c
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
printf("%d\n", a == b);
printf("%d\n", a != b);
printf("%d\n", a > b);
printf("%d\n", a < b);
printf("%d\n", a >= b);
printf("%d\n", a <= b);
return 0;
}
逻辑运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
! | 非 | !a | 如果 a 为假,则!a 为真;如果 a 为真,则!a 为假。 |
&& | 与 | a && b | 如果 a 和 b 都为真,则结果为真,否则为假。 |
|| | 或 | a || b | 如果 a 和 b 有一个为真,则结果为真,二者都为假时,结果为假。 |
示例代码:
c
#include <stdio.h>
int main() {
// &&(与),可以理解为并且
// 案例:请判断班长和他女朋友是否符合法定结婚年龄
int boy = 25;
int girl = 21;
int result = boy >= 22 && girl >= 20;
printf("%d\n", result);
// ||(或),可以理解为或者
// 案例:班长女朋友玩原神没有原石了,请帮班长判断是否有足够的钱
double wx_money = 100;
double alipay_money = 300;
result = wx_money >= 398 || alipay_money >= 398 || wx_money+alipay_money >= 398;
printf("%d\n", result);
// !(非),可以理解为不是
printf("%d\n", !0);
printf("%d\n", !!1);
// 短路规则
// && 左边为假,右边不执行
0 && printf("我是右边\n");
// || 左边为真,右边不执行
1 || printf("我是右边\n");
return 0;
}
位运算符
常见的位运算符号有&、|、^、~、>>、<<,分别代表着如下含义:
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
& | 按位与运算 | 011 & 101 | 2 个都为 1 才为 1,结果为 001 |
| | 按位或运算 | 011 | 101 | 有 1 个为 1 就为 1,结果为 111 |
^ | 按位异或运算 | 011 ^ 101 | 不同的为 1,结果为 110 |
~ | 取反运算 | ~011 | 100 |
<< | 左移运算 | 1010 << 1 | 10100 |
>> | 右移运算 | 1010 >> 1 | 0101 |
ps:取反、左右位移运算需要在补码的基础上运算。
& (与运算)
按位与(&)运算:位与位进行比较,如果都为 1,则为 1,否则为 0;
c
/**
* 按位与(&)运算:位与位进行比较,如果都为 1,则为 1,否则为 0;
* 示例:
* 40 & 15 = 8
* 0010 1000
* & 0000 1111
* -------------------
* 0000 1000
*/
printf("40 & 15 = %d\n", 40 & 15);
^ (异或运算)
按位异或运算:位与位进行比较,不同为 1,相同为 0;
c
/**
* 按位异或运算:位与位进行比较,相同为 0,不同为 1;
* 示例:
* 40 ^ 15 = 39
* 0010 1000
* ^ 0000 1111
* ------------------
* 0010 0111
*/
printf("40 ^ 15 = %d\n", 40 ^ 15);
~ (取反运算)
按位取反运算:补码取反,再将取反后的补码转为原码;
ps:无符号的数据,取反后最高位为 1,也不需要逆运算。
c
/**
* 按位取反运算:补码取反,再将取反后的补码转为原码。
* 1、正数取反:由于正数的原码和补码是相同的,取反的方式简便了些。
* 补码(原码) -> 取反 -> 补码逆运算 -> 反码逆运算(符号位不变) -> 取反后的原码
* 2、负数取反:
* 原码 -> 反码 -> 补码 -> 取反 -> 取反后的补码即原码
* 示例:
* 原码(补码)取反的补码 补码逆运算 -1 反码逆运算
* ~40 = 0010 1000 -> 1101 0111 -> 1101 0110 -> 1010 1001 = -41
*
* 原码(补码)取反的补码 补码逆运算 -1 反码逆运算
* ~15 = 0000 1111 -> 1111 0000 -> 1110 1111 -> 1001 0000 = -16
*
* 原码 反码 补码 取反
* ~-15 = 1000 1111 -> 1111 0000 -> 1111 0001 -> 0000 1110 = 14
*/
printf("~40 = %d\n", ~40);
printf("~15 = %d\n", ~15);
printf("~-15 = %d\n", ~(-15));
<< (左移运算符)
将数字的二进制补码全部向左移动,空出来的位置补 0,超出范围的二进制数丢弃;
有符号的数据左移后最高位如果为 1,则需要进行逆运算;
注意事项:
- 无符号的数据,左移后最高位为 1,也不需要逆运算;
- -128:1000 0000 特殊情况也不需要逆运算;
c
/**
* 示例:
* 40 << 4 = 0010 1000 << 4 = 1000 0000 = -128 (特殊的不需要逆运算)
* 41 << 4 = 0010 1001 << 4 = 1001 0000 = 1000 1111 = 1111 0000 = -112
* 7 6 5 4 3 2 1 0
* 1 0 0 1 0 0 0 0
*/
int8_t p = 40;
p <<= 4; // p = p << 4;
printf("40 << 4 = %d\n", p);
>> (右移运算符)
将数字的二进制补码全部向右移动,空出来的位置补什么,取决于原来的最高位是什么。原来的最高是 1 就补 1,原来的最高位是 0 就补 0 。也可以转化成这样的一句话:正数补 0,负数补 1;
c
/*
23:
0001 0111【原码】
0001 0111【反码】
0001 0111【补码】 >> 2
-----------------
0000 0101【补码】 ---> 5
*/
printf(" 23 >> 2 = %d \n" , 23 >> 2) ;
/*
-23:
1001 0111【原码】
1110 1000【反码】
1110 1001【补码】 >> 2
-----------------------------------------------
1111 1010【补码】 -> 1111 1001【反码】-> 1000 0110【原码】 ==> -6
*/
printf(" -23 >> 2 = %d \n" , -23 >> 2) ;
示例代码:
c
#include <stdio.h>
#include <inttypes.h>
int main() {
uint8_t a = 3; // 0000 0011
uint8_t b = 10; // 0000 1010
// 打印显示 2 个字符,个数不够,左边补 0
printf("%02x\n", a & b); // 0000 0010,16 进制为 02
printf("%02x\n", a | b); // 0000 1011,16 进制为 0b
printf("%02x\n", a ^ b); // 0000 1001,16 进制为 09
uint8_t c = 10; // 0000 1010
uint8_t temp = ~c; // 1111 0101
printf("%02x\n", temp); // 1111 0101,16 进制为 f5
printf("%02x\n", c << 1); // 0001 0100,16 进制为 14
printf("%02x\n", c >> 1); // 0000 0101,16 进制为 05
return 0;
}
运行结果:
c
02
0b
09
f5
14
05
位运算 - 寄存器操作
c
// 将变量 a 的第 2 位设置为 1,其他位保持不变
uint8_t a = 0b10110011; // 0xb3;
// 将变量 b 的第 2 位、第 6 位设置为 1,其他位保持不变
uint8_t b = 0b10110011; // 0xb3;
// 将变量 c 的第 5 位设置为 0,其他位保持不变
uint8_t c = 0b10110011; // 0xb3;
// 将变量 d 的第 0~3 位设置为 0,其他位保持不变
uint8_t d = 0b11111111; // 0xff;
// 将变量 e 的第 2 位取反,其他位保持不变
uint8_t e = 0b10110011; // 0xb3;
// 将变量 f 取出 8-15 位
uint32_t f = 0x12345678;
示例代码:
c
#include <stdio.h>
#include <inttypes.h>
int main() {
// 将变量 a 的第 2 位设置为 1,其他位保持不变
uint8_t a = 0b10110011; // 0xb3;
a |= (1 << 2); // 或者 x = x | (1 << 2);
printf("%02x\n", a); // b7, 10110111
// 将变量 b 的第 2 位、第 6 位设置为 1,其他位保持不变
uint8_t b = 0b10110011; // 0xb3;
b |= (1 << 2 | 1 << 6);
printf("%02x\n", b); // f7,11110111
// 将变量 c 的第 5 位设置为 0,其他位保持不变
uint8_t c = 0b10110011; // 0xb3;
c &= ~(1 << 5);
printf("%02x\n", c); // 93,10010011
// 将变量 d 的第 0~3 位设置为 0,其他位保持不变
uint8_t d = 0b11111111; // 0xff;
d &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
printf("%02x\n", d); // f0,11110000
// 将变量 e 的第 2 位取反,其他位保持不变
uint8_t e = 0b10110011; // 0xb3;
e ^= (1 << 2);
printf("%02x\n", e); // b7, 10110111
// 将变量 f 取出 8-15 位
uint32_t f = 0x12345678;
uint32_t temp = (f & 0x0000ff00) >> 8;
printf("%#x\n", temp);
return 0;
}
运算符优先级
不同的运算符默认具备不同的优先级,符号较多不用记,现用现查就可以。
当无法确定谁的优先级高时,加一个小括号就解决了。
以下优先级表,优先级数值越小,优先级越高。
优先级越高,执行的时机越早