- 1. 算术操作符
- 1.1 这里的加法减法乘法运算与数学中相同,但除则有些不同:
- 1.2 模%
- 2. 移位操作符
- 2.1 类型
- 2.2 整数在内存中的储存 - 原码 - 反码 - 补码
- 2.2.1 正整数和0
- 2.2.2 负整数
- 2.3 左移操作符 <<
- 2.4 右移操作符 >>
- 3. 位操作符
- 3.1 分类
- 3.2 按位与 &
- 3.3 按位或 |
- 3.4 按位异或 ^
- 3.5 一些例子
- 3.5.1 交换两个整数
- 3.5.2 一个整数(假设是t)在内存中的二进制形式(补码)的1的个数
- 4. 赋值操作符
- 4.1 分类
- 4.2 使用
- 5. 单目操作符 - 操作数只有一个
- 5.1 分类
- 5.2 +/-
- 5.3 ++/--
- 5.4 ! 逻辑取反
- 5.5 ~ 按位取反
- 5.6 & 取地址操作符
- 5.7 * 间接访问操作符
- 5.8 sizeof
- 5.8.1 一般使用
- 5.8.2 与数组的联系
- 5.8.3 sizeof与strlen的区别与联系
- 5.9 () 强制类型转换
- 6. 关系操作符
- 6.1 分类
- 6.2 注意事项
- 7. 逻辑操作符
- 7.1 分类
- 7.2 使用
- 7.3 短路现象
- 8. 条件操作符
- 9. 逗号表达式
- 10. 下标引用操作符
- 11. 函数调用操作符
- 12. 结构成员访问操作符
- 12.1 分类
- 12.2 使用
- 13. 表达式求值
- 13.1 隐式类型转换
- 13.1.1 整型提升
- 13.1.2 意义:
- 13.1.3 整型提升要点
- 13.1.4 例子
- 13.2 算数转换
- 13.2.1 寻常算术转换
- 13.3 操作符的属性
- 13.3.1 优先级与结合性
- 13.3.2 解释
- 13.3.3 操作符表格汇总
1. 算术操作符码字不易,若有错误,欢迎指正!
| + | - | * | / | % |
|---|---|---|---|---|
| 加 | 减 | 乘 | 除 | 模(整数取余) |
- 对于只涉及整数的除法是整数除法,其结果是两个整数的商,是一个整数。
#includeint main(){ int ret1 = 4 / 2; printf("%dn", ret1);//%d是指以有符号整型的形式打印ret1 int ret = 5 / 2; printf("%dn", ret2); return 0; }
运行结果:
- 而只要涉及到浮点数的除法就是浮点数除法,结果是一个浮点数,或者说是一个有精度的小数,与数学中的除法基本相同。
#includeint main(){ double ret1 = 4.0 / 2; double ret2 = 5.0 / 2; double ret3 = 5 / 2.0; double ret4 = 5.0 / 2.0; printf("ret1 = %dn",ret1); printf("ret2 = %dn",ret2); printf("ret3 = %dn",ret3); printf("ret4 = %dn",ret4); return 0; }
运行结果:
模操作符**只适用于整数间的运算,**结果是两个整数相除的余数并且是一个整数。
#includeint main() { int ret1 = 5 % 2; int ret2 = 4 % 2; printf("ret1 = %dn", ret1); printf("ret2 = %dn", ret2); //字符是以整数(ASCII码值)在内存中进行储存的,也可以看做整数。 char a = 10; char b = 3; int c = a % b; printf("%dn", c); return 0; }
运行结果:
2. 移位操作符 2.1 类型
| 左移操作符 | 右移操作符 |
|---|---|
| << | >> |
这里的位指的是整数在内存中储存的补码的二进制位
2.2 整数在内存中的储存 - 原码 - 反码 - 补码 2.2.1 正整数和0符号位:正整数的最高位是符号位,默认是0。
原码:由相应类型的整数直接写出的二进制形式,二进制位不够则在高位补0
正整数和0的原码、反码、补码均相同,故其补码就是其原码。
2.2.2 负整数如 int类型的整数10的二进制形式是1010,int在内存中假设占32个bit位,则补二进制位
00000000 00000000 00000000 00001010,得到int型整数10的原码,同时也是反码、补码。
符号位:负数的最高位是符号位,默认为1。
反码:符号位不变,其它位按位取反得到的二进制数。取反:0->1,1->0;
补码:反码的二进制数+1得到的二进制数。
2.3 左移操作符 <<以-10为例
二进制形式:1010
原码:10000000 00000000 00000000 00001010
反码:11111111 11111111 11111111 11110101
补码:11111111 11111111 11111111 11110110
左移操作符的操作数只能是整数。
规则:左边抛弃,右边补零
如:
#includeint main(){ int n = 5; int m = n << 1; printf("%dn", n); printf("%dn", m); return 0; }
运行结果:
把n的二进制位左移1位的结果赋值给m,故m中存放的是n << 1的值,但左移操作符并不改变n的值。
左移操作符的一个特点:以n=1,n=5为例
| n=1 | n<<1 | n<<2 | n<<3 | n<<4 | n<<5 |
|---|---|---|---|---|---|
| 2 | 4 | 8 | 16 | 32 | |
| n=5 | n<<1 | n<<2 | n<<3 | n<<4 | n<<5 |
| 10 | 20 | 40 | 80 | 160 |
n相同的情况下,随着左移位数的增加,n与n<<位数成倍数关系。
2.4 右移操作符 >>
规则:
- 算术右移
左边用原符号位填充,右边丢弃。
- 逻辑右移
不考虑符号位,左边直接用0补充,右边丢弃。
一般情况下是算术右移,因为考虑了原符号位,更加合理。
这两种右移规则对于正整数和0而言均相同,应为他们的二进制位最高位为0,不管哪种右移左边均补0。
对于负数而言这两种右移规则才有区别:
#includeint main(){ int n = -1; int m = n >> 1; printf("n = %dn", n); printf("m = %dn", m); return 0; }
分析:(以-1为例)
vs2019上的运行结果:为算数右移
C语言的算术右移对于移动负数位的行为没有进行定义,是错误的。想实现效果合理使用左移右移就可以满足。
3. 位操作符 3.1 分类
| & | 按位与 |
|---|---|
| | | 按位或 |
| ^ | 按位异或 |
注意:
- 其操作数只能是整数。
- 这里的位是二进制位
二进制对应的为相与,二者同时为1时这一位的结果才为1,否则为0。
#includeint main(){ int n = 1 & 5; printf("%dn", n); return 0; }
运行结果:
二进制对应的位相或,二者都为0时这一位的结果才为0,否则为1。
#includeint main(){ int n = 1 | 5; printf("%dn", n); return 0; }
运行结果:
二进制对应的位相异或,二者相异时为1,相同时为0。
#includeint main(){ int n = 1 ^ 5; printf("%dn", n); return 0; }
运行结果:
借助临时变量交换:
#includeint main(){ int a = 5; int b = 10; //借助临时变量t int t = 0; t = a; a = b; b = t; printf("a=%d,b=%d", a, b); return 0; }
不借助临时变量交换:
思路1:借用其中一个整数(a)存放两个整数(a+b)的和,再借助另一个整数(b)完成交换。
缺点:当a与b没有超出整型的范围但a与b的和超出了整型的范围时结果会发生错误。
#includeint main(){ int a = 5; int b = 10; printf("a=%d,b=%d", a, b); //a中存放a+b的值 a = a + b; //b中得到原来a的值 b = a - b; //a中得到原来b的值 a = a - b; printf("a=%d,b=%d", a, b); return 0; }
思路2:借助按位异或操作符实现
一个知识点:异或满足交换律, 且有 a^b^a等价于a,a^b^b等价于a,任何整数与0异或均是自身,
#includeint main(){ int a = 5; int b = 10; //a与b异或的结果存放在a中 a = a ^ b; //相当于a^b^b,得到a,赋值给b b = a ^ b; //相当于a^b^a,得到b,赋值给a a = a ^ b; return 0; }
运行结果:
借助移位操作符<<和按位与操作符&。
思路1:对于int型在内存中占4个字节或8个字节(这里以4个字节为例子),32个bit,
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx。
考虑32个位按位逐个检查,借助1,其在内存中的补码为00000000 00000000 00000000 00000001,1与一个整数按位与之后得到的结果的32个位只有最低位可能为1,其他位由于都是0,不管x是0还是1&后都是0。故可以通过判断t & 1的结果判断t二进制补码的最低位是否为1,若是0则最低位是0,若是非0则最低位为1。借助一个循环分别判断t的每一个二进制位即可。
#includeint main() { int t1 = 10; int t2 = -10; int i = 0; int cnt1 = 0; int cnt2 = 0; for (i = 0; i < 32; i++) { if (t1 & (1 << i)) { cnt1++; } if (t2 & (1 << i)) { cnt2++; } } printf("cnt1 = %d, cnt2 = %dn", cnt1, cnt2); return 0; }
运行结果:
#includeint main(){ int num = -1; int i = 0; int cnt = 0;//计数 while(num){ cnt++; num = num&(num-1); } printf("cnt = %dn",cnt); return 0; }
4. 赋值操作符 4.1 分类
| = | 赋值 |
|---|---|
| += | 加等 |
| -= | 减等 |
| *= | 乘等 |
| /= | 除等 |
| %= | 模等 |
| &= | 按位与等 |
| |= | 按位或等 |
| ^= | 按位异或等 |
| <<= | 左移等 |
| >>= | 右移等 |
一般赋值使用:
int a = 10; double b = 3.14;
连续赋值:
int a,b,c; a = b = c = 10; //等价于 c = 10; b = c; a = b;
复合赋值操作符:
int a,b; a = 5; b = 10; a += b; //等价于a = a + b a &= b; //等价于a = a ^ b
5. 单目操作符 - 操作数只有一个 5.1 分类
| + | 正值 |
|---|---|
| - | 负值 |
| ++ | 自增(有前缀和后缀两种形式) |
| – | 自减(有前缀和后缀两种形式) |
| ! | 逻辑取反 |
| ~ | 按位取反(二进制形式) |
| & | 取地址 |
| * | 解引用(间接访问) |
| (类型) | 强制类型转换 |
| sizeof | 操作数的类型长度(单位是字节) |
+:是一个操作符,但很少使用,对于整数不需要,对于负数不起作用。
-:把一个正数变为负数,把一个负数变为正数。
int a = 10; a = +a;//a == 10 a = -a;//a == -10 int b; b = -a;//b == 105.3 ++/–
++:
int a = 10; a++; --a; //等价于a = a + 1; //等价于a += 1;
前缀形式++a符合先自增再使用,a先增加1,接着再使用a,用的是a自增后的值。
后缀形式a++符合先使用再自增,a先使用,接着再自增a,用的是a自增前的值。
–:同++。
5.4 ! 逻辑取反C语言在判断真假时,以0表示假,非0表示真。
对0进行逻辑取反!0结果是真(非0)。
对非零值进行逻辑取反如!10结果是假(0)。
#includeint main(){ int a = 0; printf("!a = %dn", !a); int b = 10; printf("!b = %dn", !b); return 0; }
运行结果:
按一个整数的二进制补码形式取反,0变1,1变0。
int a = 10;
int b = ~a;
printf("b = %dn", b);
00000000 00000000 00000000 0000101010的二进制补码
11111111 11111111 11111111 11110101~10
11111111 11111111 11111111 11110100~10的反码
10000000 00000000 00000000 00001011~10的原码
运行结果:
取出操作数在内存中的地址。
操作数可以是变量,字符串常量,函数,数组,结构体等。
#includeint main(){ int a = 10; //创建一个指针变量p存放变量a的地址 int* p = &a; printf("%pn", &a); printf("%pn", p); return 0; }
运行结果:
- 对于一个具有具体指向的指针变量p(假设其指向整型变量a)来说,已经知道p中存放的是变量a的地址,可以通过间接访问操作符*得到变量a的值,获得使用和改变变量a的值的权限(如果对p没有主动做出限制的话)。
- 与指针紧密相关。
#includeint main(){ int a = 10; int p = &a; printf("*p = %dn", *p); *p = -10; printf("%dn", *p); return 0; }
运行结果:
计算的是操作数类型内存中所占字节的大小,以字节为单位。
5.8.1 一般使用注意:类型本身并不占内存的大小,即不在内存中开辟空间。但当创建了某种类型的变量时就会在内存中开辟该类型相应大小的空间。
#includeint main(){ int a = 10; printf("sizeof(a) = %d", sizeof(a)); printf("sizeof(int) = %d", sizeof(int)); //sizeof操作符的括号可以省略,但在计算类型时是不能省略的 printf("sizeof(a) = %d", sizeof a); //printf("sizeof int = %d", sizeof int);此为错误用法 return 0; }
运行结果:
在数组进阶中已经提到过,在回顾一下。
数组名一般情况下表示数组首元素的地址,但有两个例外。
- 数组名单独遇到sizeof时计算的是整个数组的大小。
- 数组名遇到&时,取出的是整个数组的地址。
#includevoid test(char s[]); int main(){ char str[10] = {0}; //这里计算的是整个字符数组的大小 printf("sizeof(str) = %dn", sizeof(str)); test(str); return 0; } //这是个测试 //等价于 //void test (char* s) void test(char s[]){ //这里计算的是一个字符指针的大小。 printf("sizeof(s) = %dn", sizeof(s)); }
一个指针的大小可能是4字节或8字节。
运行结果:
- 两者都可以计算大小
- sizeof计算的是实际占内存中的储存单元的大小。
- sizeof是操作符,strlen()是C语言的(头文件string.h)库函数。
- strlen()函数计算的是字符串的长度,不包括字符串末尾的字符'0'。
- sizeof的括号可以去掉,但strlen()的括号不能去掉,这是strlen()函数的一个特征。
一个例子:
#include5.9 () 强制类型转换#include int main(){ char str[20] = "Hello,World!"; printf("sizeof(str) = %dn", sizeof(str)); printf("strlen(str) = %dn", strlen(str)); return 0; }
把操作数强制转换为想要的类型。若不使用强制类型转化可能会产生警告。
#includeint main(){ //这种情况会产生警告信息,3.14被默认为浮点型数据,被赋值给int型变量a时会丢失精度,是隐式类 //型转换 int a = 3.14; printf("a = %dn", a); //强制类型转化,明确把浮点型数据转换为int型数据 int b = (int)3.14; printf("b = %dn", b); return 0; }
6. 关系操作符 6.1 分类
| > | 大于 |
|---|---|
| >= | 大于等于 |
| < | 小于 |
| <= | 小于等于 |
| != | 不等于 |
| == | 等于 |
- 等于是两个等号,赋值是一个等号,非常容易在这里出错。
- 两个浮点型数据比较是否相等时不能直接比较,因为浮点数在内存中不能精确储存,总要损失一些精度。需要比较连个浮点数的差值的绝对值是否近似为0。即与一个非常小(如1e-5)的数相比较。
#includeint main(){ double a = 3.14; float b = 3.14; //1e-5 == 0.00001 if(fabs(a-b) < 1e-5){ printf("a==bn"); } else if(a-b > 1e-5){ printf("a > bn"); } else{ printf("a < bn"); } return 0; }
运行结果:
7.1 分类注意与按位与&按位或 |的区别:
- &、|是对二进制位进行操作。
- &&、||关注的是值的真和假,不是二进制的位。
| && | 逻辑与 |
|---|---|
| || | 逻辑或 |
&&、||是双目操作符,有两个操作数。
对于&&,当两个操作数都为真时,表达式的结果才为真(1),其他情况均为假(0)。
对于||,当两个操作数都为假时,表达式的结果才为假(0),其他情况均为真(0)。
这里的操作数可以使复杂的表达式。
例子:判断闰年
#include7.3 短路现象int main(){ int year = 0; scanf("%d", &year); if(year%4 == 0 && year%100 != 0 || year%400 == 0){ printf("isleapn"); } else{ printf("is not leap"); } return 0; }
a与b均表示表达式。
- 对于&&,如a&&b,当子表达式a为假(0)时,整个表达式的值就是0,后面的子表达式b不在计算,子表达式b相当于被短路了。
- 对于||,如a||b,当子表达式a为真(非0)时,整个表达式的值就是1,后面的子表达式b不再计算,子表达式b相当于被短路了。
8. 条件操作符
格式:表达式1 ? 表达式2 : 表达式3
用法类似于ifelse语句,表达式1为真时整个表达式的值是表达式2的值,表达式1为假时整个表达式的值是表达式3的值。
一个例子:
#includeint main() { int a, b; scanf("%d%d", &a, &b); int max = a > b ? a : b; printf("max = %d", max); return 0; }
运行结果:
9. 逗号表达式
格式:表达式1,表达式2,表达式3,...,表达式n;
逗号表达式的最终的值是表达式n的值,表达式n之前的表达式可能会影响表达式n的值,也就是影响逗号表达式的值。
一个例子:
#includeint main() { int a, b, c, d; int t1 = (a = 5, b = 3, c = 1, d = 10); int t2 = (a = 5, b = 3, c = 1, d = a + b + c); printf("t1 = %dn", t1); printf("t2 = %dn", t2); return 0; }
运行结果:
10. 下标引用操作符
格式 数组名[索引值],操作数有两个:数组名与索引值(或者说下标)。索引值范围0~数组长度-1。
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int a = arr[3];//3[arr]与arr[3]等价
访问时,这里的arr[3]与3[arr]等价,下标引用操作符是二元操作符,两个操作数可以互换,类比其他二元操作符。但类似3[arr]不好理解。
arr[3]可以写为*(arr+3)或*(3+arr)
数组定义时则不行。
11. 函数调用操作符
格式 函数名(可能有的一个或多个函数参数)
函数调用操作符的操作数至少有一个函数名,函数参数可能有一个或多个也可能没有函数参数。
一个例子:
#includeint test1(int a, int b); void test2(); int main(){ int a,b; scanf("%d%d", &a, &b); test1(a, b); test2(); return 0; } //测试1 int test1(int a, int b){ return a > b ? a : b; } //测试2 void test2(){ printf("test2n"); return; }
运行结果:
12. 结构成员访问操作符 12.1 分类
| . | 圆点访问操作符(结构体) |
|---|---|
| -> | 箭头访问操作符(结构指针) |
#include//定义一个学生的结构体类型并用typedef重命名为STU typedef struct student{ char name[20]; char id[15];//学号 int score; }STU; int main() { STU stu; scanf("%s %s %d", stu.name, stu.id, &stu.score); printf("%s %s %dn", stu.name, stu.id, stu.score); STU* p = &stu; scanf("%s %s %d", stu.name, stu.id, &stu.score); printf("%s %s %dn", p->name, p->id, p->score); return 0; }
13. 表达式求值 13.1 隐式类型转换 13.1.1 整型提升
13.1.2 意义:C的整型算术运算总是至少以缺省(或者说是默认)整型类型的精度进行的。
13.1.3 整型提升要点
- 表达式的整型运算要在CPU的相应运算器件内运行,CPU内整型运算器(AUL)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。所以对于运算中低于CPU内整型操作数的标准长度的情况,要先转换为CPU内整型操作数的标准长度在进行计算。
- 通用CPU难以实现两个8比特字节直接相加计算,所以表达式中各种长度的可能小于int长度的整型值,必须先转换为int或unsigned int,然后再送入CPU进行运算。
按照变量的数据类型的符号位进行提升的。
对于无符号整数高位直接补0
对于有符号整数
13.1.4 例子正数:char a = 1;
1的二进制补码为00000001
整型提升(高位补0)之后00000000 00000000 00000000 00000001
负数:char b = -1;
-1的二进制补码为11111111
整型提升(高位补1)之后11111111 11111111 11111111 11111111
#includeint main(){ //char、short、int默认为有符号类型,若整型提升则进行的是有符号整数的整形提升 char a = 0xf6; //11110110 short b = 0xf600; //11110110 00000000 int c = 0xf6000000; //11110110 00000000 00000000 00000000 //参与运算之前先对char、short进行整形提升为int if(a == 0xf6){ //11111111 11111111 11111111 11110110 printf("a == 0xf6n"); } if(b == 0xf600){ //11111111 11111111 11110110 00000000 printf("b == 0xf600n"); } if(c == 0xf6000000){ //11110110 00000000 00000000 00000000 printf("c == 0xf6000000n"); } return 0; }
运行结果:
#include13.2 算数转换int main(){ char a = 1; printf("sizeof(a) = %un", sizeof(a)); //+a是一个表达式,sizeof计算的是a整形提升之后的大小,但+a、-a是实际上没有进行计算的。 printf("sizeof(+a) = %un", sizeof(+a)); //-a是一个表达式,sizeof计算的是a整形提升之后的大小 printf("sizeof(-a) = %un", sizeof(-a)); return 0; }
13.2.1 寻常算术转换同一个操作符的操作数类型不同时便无法继续进行运算,必须要转换为同一种类型才能继续进行算术运算。
| long double | 多精度浮点类型(长精度浮点类型) |
|---|---|
| double | 双精度浮点型 |
| float | 单精度浮点型 |
| unsigned long int | 无符号长整型 |
| long int | 长整型 |
| unsigned int | 无符号整型 |
| int | 有符号整型 |
若运算中出现多种类型的数据,优先转换顺序为:int ------>long double
如果不遵守优先转换顺序可能会造成数据精度丢失。
- 优先级
- 结合性 - 左结合性与右结合性
- 是否控制求值顺序
13.3.2 解释与表达式的属性相区别:值属性与类型属性。
两个相邻的操作符,先看优先级的高低,优先级高的先进行运算;
若优先级相同,则看结合性,按结合性规定的顺序进行运算。
注意:
- 优先级与结合性管的是两个相邻的操作符。
- 间隔开的操作符之间不受优先级与结合性的限制。
例如:int a = 1*2 + 3*4 + 5*6;
有优先级知道:
第一个号比第一个+号先进行运算;
第二个号比第一个+号和第二个+号先进行运算;
第三个号比第二个+号先进行运算;
但:
不知道第一个号是否比第二个+号运算的早;
不知道第三个*号是否比第一个+号运算的早。
一个有歧义的表达式:
int a = b + --b;
知道--操作符比+操作符先进行运算;
但
不知道b 与 --b两个操作数谁先进行。
闭坑指南:我们写表达式时要确定表达式有唯一确定的值,如果不确定就需要重新写或对表达式进行合理拆分,使其成为几个简单的表达式。
13.3.3 操作符表格汇总| 操作符 | 描述 | 用法 | 结果类型 | 结合性 | 是否控制求值顺序 |
|---|---|---|---|---|---|
| () | 括号 | (表达式) | 与表达式相同 | 无 | 否 |
| () | 函数调用 | 函数名(函数参数) | 函数返回类型 | L | 否 |
| [ ] | 下标引用 | 数组名[下标] | 数组元素类型 | L | 否 |
| . | 结构成员访问 | 结构名.结构成员 | 结构成员类型 | L | 否 |
| -> | (结构指针)箭头访问 | 结构指针->结构成员 | 结构成员类型 | L | 否 |
| ++ | 后缀自增 | a++ | 自身类型 | L | 否 |
| – | 后缀自减 | a++ | 自身类型 | L | 否 |
| ! | 逻辑反 | !a | R | 否 | |
| ~ | 按位取反 | ~a | R | 否 | |
| + | 正值 | +a | 自身类型 | R | 否 |
| - | 负值 | -a | 自身类型 | R | 否 |
| ++ | 前缀自增 | ++a | 自身类型 | R | 否 |
| – | 前缀自减 | –a | 自身类型 | R | 否 |
| ***** | 间接访问 | *a | 指针所指向的类型 | R | 否 |
| & | 取地址 | &a | 指针类型 | R | 否 |
| sizeof | 计算长度,单位字节 | sizeof(a) | 整型 | R | 否 |
| (类型) | 强制类型转换 | (类型)a | 强制转换的类型 | R | 否 |
| * | 乘法 | a*b | L | 否 | |
| / | 除法 | a/b | L | 否 | |
| % | 模 | a%b | 整型 | L | 否 |
| + | 加法 | a+b | L | 否 | |
| - | 减法 | a-b | L | 否 | |
| << | 左移 | a<<1 | 整型 | L | 否 |
| >> | 右移 | a>>1 | 整型 | L | 否 |
| > | 大于 | a>b | 整型 | L | 否 |
| >= | 大于等于 | a>=b | 整型 | L | 否 |
| < | 小于 | a | 整型 | L | 否 |
| <= | 小于等于 | a<=b | 整型 | L | 否 |
| == | 等于 | a==b | 整型 | L | 否 |
| != | 不等于 | a!=b | 整型 | L | 否 |
| & | 按位与 | a & b | 整型 | L | 否 |
| ^ | 按位异或 | a ^ b | 整型 | L | 否 |
| | | 按位或 | a | b | 整型 | L | 否 |
| && | 逻辑与 | a && b | 整型 | L | 是 |
| || | 逻辑或 | a || b | 整型 | L | 是 |
| ? : | 条件操作符 | a ? b : c | 无 | 是 | |
| = | 赋值 | a = 1 | R | 否 | |
| += | 加等 | a += 1 | R | 否 | |
| -+ | 减等 | a -= 1 | R | 否 | |
| *= | 乘等 | *a = 1 | R | 否 | |
| /= | 除等 | a /= 1 | R | 否 | |
| %= | 模等 | a %= 2 | 整型 | R | 否 |
| <<= | 左移等 | a <<= 1 | 整型 | R | 否 |
| >>= | 右移等 | a >>= 1 | 整型 | R | 否 |
| &= | 按位与等 | a &= 1 | 整型 | R | 否 |
| ^= | 按位异或等 | a ^ 1 | 整型 | R | 否 |
| |= | 按位或等 | a |= 1 | 整型 | R | 否 |
| , | 逗号 | a,b,c,…,n | L | 是 |
END



