C语言运算符
表达式和表达式语句
表达式:通过一些操作有返回的值的 , a < b
返回 1 或者 0
赋值符号的也是表达式,这边表达的是的意思是要看,赋值之后的接受是零还是非零。零为 false , 非零为true
int a = 12;
int b = 10;
// 将 b 的值赋值给 a , 赋值后 a 的值如果是非零的就是 true ,如果是零就是 false
if(a=b) {
printf("a == b ");
}else {
printf("a != b ");
}
表达式语句
表达式语句:执行一个表达式,但是不会返回任何结果。
常见的有:
- 初始化变量
- 条件语句
if
- 循环语句
while
运算符
算数运算符
包含:+
,-
,*
,/
,%
其中:
- 整数型数据使用除法时得到结果仍然是取整后的整数,浮点型想除得到的是小数
%
取余数运算符只能针对整数
以上运算符都是二元运算符(双目运算符), 运算符要能执行左右两端都需要有表达式,左右各一个表达式相加等于二
自增自减运算符
解释:
++
自增运算符,表示变量自身的值加一--
自减运算符,表示变量自身的值加一
注意: ++a
表示先自增再取值 a++
表示先取值再自增, --a
先自减再取值 a--
先取值再自减
自增自减运算符是一个一元运算符, 优先级口诀: 一般情况下一元运算符有限级高于二元运算符高于三元运算符
int i= 3
扩展: +=
-=
*=
/=
二元运算符
例子:
a += 2; // a = a + 2 简写
a -= 1; // a = a - 1 简写
a *= 3; // a = a * 3 简写
a /= 2; // a = a / 2 简写
逻辑运算符
用于条件判断的运算符,表达复杂的条件关系
- 逻辑与 && (且),该运算符是一个二元运算符,左右两端表达式都要为真,结果才为真,有一个为假返回值就是假
int age = 18;
int money = 200;
if(age >= 18 && money >= 200) {
printf("恭喜你成为本网吧的vip用户!");
}
注意: 且运算符逻辑两者都真才返回真,若且运算符第一项表达式已经为假后面的表达式将不会执行。通过这一特点在开发中经常会使用 && 运算符进行 惰性运算
int a = 1
int b = 2
int ret = a < b && a++
- 逻辑或 || (且),该运算符是一个二元运算符,左右两端表达式只要有一个为真,结果就为真.两者都为假返回值才是假
int age = 18;
int money = 200;
if(age >= 18 || money >= 200) {
printf("恭喜你成为本网吧的vip用户!");
}
注意: 逻辑或也支持惰性运算,若且运算符前面的表达式为真,后面的表达式不执行,
int id = 0;
id || (id = 5);
id || (id = 7);
id || (id = 9);
id || (id = 12);
id || (id = 24);
printf("%d \n", id); // 5
- 逻辑非(
!
) 是一元运算符,将逻辑表达式的值取反
int age = 18;
if(!(age >= 18)) {
printf("你还未成年\n");
}
bool show = true;
if(show) {
printf("显示\n");
}
if(!show) {
printf("隐藏\n");
}
优先级: !
> &&
> ||
关系运算符
包含
>
大于<
小于>=
大于等于<=
小于等于==
等于!=
不等于
以上全是二元运算符,在使用避免出错:
if( 100 >= score >= 90) // 错误代码,不能这么写
if( 100 >= score && score >= 90) // 正确写法
一定要区分 =
和 ==
: =
是赋值操作 ==
判断两者是否相同
int a =1 , b =2 ;
a == b =2 ; // 编译报错,原因: == 优先级比 = 的优先级高 , 所以 0 = 2 ,常量是不能作为左值的
位运算符
位运算符操作的对象是数据二进制编码中的每一位
&
: 位逻辑与 a & b 将变量 a 和 b 逐位进行与操作(0与上任何数都为0)
12 & 15 // 1100 & 1111 -> 1100
使用 &
可以实现获取 char 类型的最后一半的字节比如 : 0x45
就可以获取到 0x05
unsigend char temp = 0x45;
// 0x45 ---> 0100 0101
// 0x0f ---> & 1111 1111
// 0x05 ---> 0000 0101
unsigned char lamp = temp & 0x0f;
printf("灯:%#x \n", lamp);
// 获取前面一半的字节使用 >> , 无符号的 ,高位补零,低位溢出。
// 0x45 ---> 0100 0101
//0x04 ----> 0000 0100
unsigend dour = temp >> 4;
printf("灯:%#x \n", lamp);
|
: 位逻辑或a | b将变量 a 和 b 逐位进行或操作(1或上任何数都为1)
12 | 15 // 1100 | 1111 -> 1111
~
: 位逻辑反 ~a 将变量 a 中的每一位取反
unsigned char a = 1; // 0000 0001
printf("位运算或 %hu \n", ~a); // 1111 1111 1111 1110 -> 65534
^
: 位逻辑异或 a ^ b
将变量 a 和 b 逐位进行异或操作(相同为0,不同为1)
12 ^ 14 // 1100 ^ 1110 -> 0010
推导: a ^ a -> 0
, a ^ 0 -> a
利用位异或来实现两数交换
#include <stdio.h>
int main(int argc, const char* argv[]) {
// 方案1 : 中间变量
int a = 12, b = 15;
int temp;
// temp = a;
// a = b;
// b = temp;
// printf("a = %d b = %d ", a, b);
// 方案二:加减法
// a = a + b; // 12 + 15
// b = a - b ; // 12 + 15 - 15 b = 12
// a = a - b; // 12 + 15 - 12 a = 15
// printf("a = %d b = %d ", a, b);
// 方案三:异或
a = a ^ b; // a ^ b
b = a ^ b; // a ^ b ^ b b = a
a = a ^ b; // a ^ b ^ b => ( b = a ) ===> a ^ b ^ a
printf("a = %d b = %d ", a, b);
return 0;
}
技巧:
- 任何数 ^ 自己都等于 0 ,(异或运算:相同为 0 )
- 任何数 ^ 0 都等于自己本身 ,(异或运算:相同为 0 , 所有的 1 都保留下来
a ^ a ^ a
等于本身 ) - 任何数异或自己数据类型的最大值,等于 最大值 - 自己
char a = -1;
char b = a ^ 128;
printf("%d \n", b); // 255 - 128 = 127
return 0;
<<
: 数据本身向高位(左)移动 n 位,溢出的被舍弃,低位补0
int a = 0x00112233
例子
int r = 0xff;
int g = 0xcc;
int b = 0x00;
int alph = 0x77;
// 0xff000000 | 0x00cc0000 | 0x0000 | 0x77
int color = r << 24 | g << 16 | b << 8 | alph;
printf("%#x\n", color); // 0xffcc0077
printf("%#x", 0x01<<2);
技巧:
- 每一位相等于 * 2
示例:利用 <<
和 |
来实现使用一个 int
数据类型的变量来存储一个颜色
// 利用 int 来存储一个颜色 , int 每一个字节都存一个三原色
// #fffc5531 a(透明度)r(红色)g(绿色)b(蓝色)
// 这里一定无符号的,应为在 int 除了第一个字节,都是可以存储 0 - 255 的,这里由于要存储颜色颜色也是0 - 255,
// 所有这里一定要使用 无符号的 char , 如果是有符号就会出现溢出问题
unsigned char a = 0xff;
unsigned char b = 0xfc;
unsigned char c = 0x55;
unsigned char d = 0x31;
// 利用 << (左移) 将数据放在对应的位置,利用 | (位或) 拼接其他的数据
// 0xff000000
// | 0xfffc0000 // 利用位或来拼接其他的数据。
int color = a << 24 | b << 16 | c << 8 | d ;
printf("%#x \n ", color);
>>
: 数据本身向低位移动
- 算数右移: 数据向低位移动, 越界低位被舍弃,高位补符号位
- 逻辑右移: 数据向低位移动, 越界低位被舍弃,高位补0
注意: 不同操作系统采用右移方式是不同的
如: Ubuntu 和 windows 采用的算数右移
示例:
// 右移:无符号:高位补零 ,低位溢出舍去
unsigned int a = 0x7f000000;
printf("%#x \n", a);
printf("%#x \n", a >> 8);
// 右移: 有符号,高位补符号位,低位溢出舍去
int a1 = 0x8f000000; // 0x8f000000 的符号位是 1
printf("%#x \n", a1); // 0x8f000000
printf("%#x \n", a1 >> 8); // 高位补符号位: 也就是 1 , (1111 = 0xf ) 0xff8f0000
// 右移: 有符号,高位补符号位,低位溢出舍去
int a2 = 0x7f000000; // 0x7f000000 的符号位是 0
printf("%#x \n", a2); // 0x7f000000
printf("%#x \n", a2 >> 8); // 高位补符号位 :也就是 0 , 0000 0000 0000 0000 0111 1111 0000 0000 0000
扩展 >>=
<<=
自身右移自身左移
a <<= 2 等价 a = a << 2
a >>= 2 等价 a = a >> 2
作业
- 一个整数a,
要求把a的第五个二进制位变成0(无论是否为0),其他二进制不允许改变
1011 1001
&1110 1111
~0001 0000 等于上者
// 答案: a & ~0x10
要求把a的第五个二进制位变成1(无论是否为1),其他二进制不允许改变
1011 1001
|0001 0000
答案: a | 0x10
要求把a的第五个二进制位取反(0变成1,1变成0),其他二进制不允许改变
1011 1001
^0001 0000
答案: a ^ 0x10
- 0x01 << 5 的16进制结果是多少??
0000 0001 -> 0010 0000
0x20
- 以下程序的执行结果是
int x='f';
printf("%c\n",'a'+(x-'a'+1)); // g
- 以下程序的执行结果是
int a=4,b=5,c=0,d;
d=!a&&!b||!c;
printf("%d\n",d); // 1
- 以下程序的执行结果是
int a,b,c,d;
a=10;
b=a++; // 10
c=++a; // 12
d=10*a++; // 120
printf("b,c,d:%d %d %d\n",b,c,d);
三目运算符
语法: 表达式1 ? 表达式2 : 表达式3
首先先判断表达式1,若为真返回表达式2的值,若为假返回表达式3的值
int is_adult = age >= 18 ? 1 : 0;
// 求两者的最大值
int max = a > b ? a : b
sizeof运算符
求数据类型,变量的大小
sizeof(bool);
int a = 4;
sizeof(a)
逗号运算符
符号: ,
作用:将多行代码写成一行,从前往后执行。
如果涉及到赋值,返回值是最后一个逗号的。
示例:
int a ;
int b;
// 不使用 ,逗号
a = 20 ;
b = 20 ;
// 使用逗号
a = 20 , b = 20;
int c = (a++, 10 + 5);
printf("%d %d \n" , a , c ); // 21 12
优先级
小技巧:
- 一元 > 二元 > 三元
- 越精确优先级越高
- 赋值最低。
- 一般:算数运算( + 、 - 等 ) > 关系运算 (&& 、|| 等 ) > 赋值运算 ()