操作符
文章目录
1. 算术操作符
+ - * / %
加减乘除我们就不多说了,会涉及到数据转换,详细请看数据类型篇。
//1.%求余数的妙用
//s=i%5;这说明s的取值只能是0 1 2 3 4,但是数据有可能会溢出,所以这时候我们需要用 unsigned,才让他重新回到0。
//0%5 ——》》0除5等于0余0
//1%5 ——》》0除5等于0余1
for (unsigned char a = 125; a < 256; a++)//永远到达不了256,无线循环
{
printf("%d\n",a%4);
}
2. 移位操作符
>>右移操作符
<<左移操作符
我们知道,计算机里面存储数据的方式是以反码的形式进行存储,那么移位操作符就是移位计算机中反码的二进制位。
对于移位运算符,不要移动负数位,num<<-1是错误的。
2.1 左移操作符
左边抛弃、右边补0
//2.操作符
int num = 10;
num=num<<1;
// 00000000 00000000 00000000 00001010
//去(0) 00000000 00000000 00000000 0001010(0)补
printf("%d",num);//
2.2 右移操作符
- 逻辑移位:左边用0填充,右边丢弃
- 算术移位:左边用原该值的符号位填充,右边丢弃
计算机采用的是算术移位,符号填充,右边丢弃
//2.操作符
int main()
{
int num = -2;
num = num >> 1;
// 11111111 11111111 11111111 11111110 (补码形式)
// 补(1)1111111 11111111 11111111 11111111 去(0)
printf("%d", num);//-1
return 0;
}
3. 位操作符
& ^ |(与、异或、或)
位操作符对补码形式行进位操作。
3.1 &与操作符用于对某一位进行清0,在单片机中对寄存器操作
0110 0011 & 1101 1111=0100 0011(单片机用法)
常用来清零某位,其他位可以不变,0很重要
3.2 |或操作用于对某一位置1
0011 0011 | 1000 0000=1011 0011
常用来置1某位,然后其他位不变
不能创建临时变量(第三个变量),实现两个数的交换。
方法1:
a=5,b=3;
a=a+b;(容易溢出)
b=a-b;
a=a-b;
方法2;0101 ^ 0011(没有进位)
a=a^b;0110
b=a^b;0101 5b=a^b^b=a^0=a;
a=a^b;00113
//3.位操作符
int main()
{
int a = 3, b = 5; // 0011 0101
a = a ^ b; //0110 = 0011 0101
b = a ^ b; //0011 = 0110 0101
a = a ^ b;
printf("%d\n",a);
printf("%d\n",b);
}
4. 赋值操作符
= += -= *= /= &= ^= |= >>= <<=
这个就不多说了。
5. 单目操作符
-
! 逻辑反操作a=5;!a=0;
-
~ 对一个数的二进制按位取反a=5;~a=-6
-
& 取地址
-
sizeof 操作数的类型长度(以字节为单位)sizeof()括号可以省略,所以他是一个操作符,不是函数。计算数组元素大小=sizeof(arr)/sizeof(arr[0])
-
– 前置、后置
-
++ 前置、后置
b=++a;先加加后使用
b=a++;先使用后加加 -
*间接访问操作符(解引用操作符)
int p=&a;*p=5解引用指针p;a=5 -
(类型) 强制类型转换
6. 关系操作符
>=
<
<=
!= 用于测试“不相等”
== 用于测试“相等”
7. 逻辑操作符
&& 逻辑与
|| 逻辑或
//4.逻辑操作符&& ||
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
// a++ 后置++__a=a+1,因为a先使用了,所以与后面&&等于0,编译器会直接忽略后面的不计算
printf(" a = %d\n b = %d\n c = %d\n d = %d\n i = %d\n", a, b, c, d,i); //1 2 3 4 i=0;
return 0;
}
8. 条件操作符(三目运算符)
exp1 ? exp2 : exp3
a=exp1 ? exp2 : exp3;如果是真,那么a=exp2
在return 中的使用
return exp1 ? exp2 : exp3;正确用法
exp1 ? return exp2 : return exp3;//错误用法
9. 逗号表达式
exp1, exp2, exp3, …expN
以最后一个表达式的结果为结果
10. 下标引用、函数调用和结构成员
[]
() 函数调用操作符
.
->结构体引用
11. 整形提升
C的整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
//5.整型提升
int main()
{
char c = 1;
printf("%u\n", sizeof(c));
printf("%u\n", sizeof(+c)); //提升,这里C++和++C都不行,因为C=C+1,已经运算完然后回归char型了,这里是数据类型运算
printf("%u\n", sizeof(-c)); //提升
printf("%u\n", c);
//1 4 4 1
return 0;
}
int a;
int b;
a+b;//每个变量都有两个属性,值属性和类型属性
我们上面说sizeof不参与运算,的确是的,他printf(“%u\n”, sizeof(1+c));这里只要类型属性就够了,它不需要值属性,所以C从头到尾都是1
12. 操作符的属性
虽然我们知道了操作符的优先级,但是有些代码还是错误的
//6.操作符的属性
#include<stdio.h>
int fun()
{
static int count = 1;
return ++count;
}
int main()
{
int answer;
answer = fun() - (fun() * fun());//这里涉及到,如果按照优先级应该是 4-2*3=1;但是编译器先准备的是前面的 2-3*4=-10
printf("%d\n", answer);//输出-10
return 0;
}
int main()
{
int a = 2;
int* p = &a;
*p++;//后置++,故意让你先解引用。*p没做什么操作,然后p+1,所以p=&a+1,a=2
printf("%p,%p,%d",&a,p, a);
return 0;
}
总结:
对于操作符,我们有些时候很难记清他们的操作符,比如+= *=的这种优先级很低,前置和后置++的优先级很高,只不过他的意图是先让你运用还是先让你++又或者a=1,(++a)+(++a)+(++a)的结果是不确定的,因为我们不知道到底先准备a还是先++,如果先准备a,那么所有a都相同,如果先++,a不同
所以,面对大量的运算符,我们最好多用一些括号。