「C 语言」5 操作符详解
操作符详解
算术操作符
+ - * / %
//除法算出的是 商
int a = 5 / 2;//商2余1 - 整数除法
//将除号左右的一个数字改为小数
double b = 5.0 / 2;
printf("%lf", b);//默认打印6位小数
//取模的左右操作数必须是整数
移位操作符
作用于整数
>> <<
int main()
{
int a = -1;
//移动二进制位 - 补码的二进制位
int b = a >> 1;//算术移位 - 通常
//10000000000000000000000000000001 - 原码
//11111111111111111111111111111110 - 反码
//11111111111111111111111111111111 - 补码
printf("%d", b);//-1
}
右移操作符
算术右移
右边丢弃,左边补原符号位
逻辑右移
右边丢弃,左边补0
左移操作符
左边丢弃,右边补0
警告: 对于移位运算符,不要移动负数位,这是未定义的。
位操作符
& | ^
按二进制位
同样以补码进行运算
不创建临时变量,交换两个变量的值
溢出
int a = a + b; int b = a - b; int a = a - b;
不溢出
int a = a ^ b; int b = a ^ b; int a = a ^ b;
计算一个数字补码中1的个数
正常操作,需要不停地判断循环
//循环 /2 判断
采用按位与运算,32次
//num & 1; - 得到num的最低位
#include<stdio.h>
int main()
{
int num = ;
int count = 0;
for (int i = 0;i<32;i++)
{
if ((num>>1)&1 == 1)
count+=;
}
printf("%d",count);
return 0;
}
精简的减少循环次数,但是不容易想到
#include<stdio.h>
int main()
{
int num = ;
int count = 0;
while (num)
{
count++;
num = num & (num-1);
}
printf("%d",count);
return 0;
}
赋值操作符
int weight = 120;//初始化
weight = 89;//不满意赋值
double salary = 10000.0;
salary = 50000.0;
赋值操作符可以连续使用(不推荐)
a = x = y+1;
//连续赋值
清晰而易于调试的写法
x = y+1;
a = x;
复合赋值符
+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=
单目操作符
只有一个操作数
! //逻辑反操作
- //负值
+ //正值
& //取地址
sizeof //操作数的类型长度(以字节为单位)
~ //对一个数的二进制位取反
-- //前置、后置--
++ //前置后置++;
* //间接访问操作符(解引用操作符)
(类型) //强制类型转换
数组的类型(去掉数组名)
printf("%d",sizeof(int [10]))
sizeof()
后加变量名可以省略括号
#include<stdio.h>
int main()
{
short s = 0;
int a = 10;
printf("%d\n",sizeof(s = a + 5));//2
printf("%d\n",s);//0
return 0;
表达式的结果要放在s
中,只是短整型;而sizeof
中的表达式不参与运算
#include<stdio.h>
int main()
{
int a = 0;
int x = ~a;
printf("%d\n",x);//-1
return 0;
}
//00000000000000000000000000000000
//11111111111111111111111111111111 - 补码
//11111111111111111111111111111110 - 反码
//10000000000000000000000000000001 - 原码
#include<stdio.h>
int main()
{
int a = 11;
int b = a | (1<<2);//将第三位的0变成1
//00000000000000000000000000001011
//00000000000000000000000000000100
int c = b & ~((1<<2));//将第三位的1还原成0
//00000000000000000000000000001111
//11111111111111111111111111111011
return 0;
}
++
与--
的前置后置表示先加减还是先使用
关系操作符
大于小于等于不等于
逻辑操作符
&& //逻辑与
|| //逻辑或
要与按位与/或区分开,相当于 et 和 ou
&&
的左边如果是假,则右边不会再计算
||
的左边如果是真,则右边不会再计算
EXo
#include<stdio.h>
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
printf("%d %d %d %d\n",a,b,c,d);//1 2 3 4
i = a-- && ++b && d++;
printf("%d %d %d %d\n",a,b,c,d);//0 3 3 4
i = a++ || ++b || d++;
printf("%d %d %d %d\n",a,b,c,d);//1 4 3 5
i = a++ || ++b || d++;
printf("%d %d %d %d\n",a,b,c,d);//2 4 3 5
return 0;
}
条件操作符
exp1 ? exp2 : exp3
逗号表达式
就是用逗号隔开的多个表达式,从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
int a = 1;
int b = 1;
int c = (a>b, a=b+10, a, b=a+1);
//c=?
//c = 13
if (a=b+1, c=a/2, d>0);
//真正判断的是d>0
//bofore
a = get_val();
count_val(a);
while (a>0)
{
//{业务处理}
a = get_val();
count_val(a);
}
//用逗号表达式改写
while (a = get_val, count_val(a), a>0)
{
//{业务处理}
}
下标引用、函数调用和结构成员
[]
,下标引用()
,操作数是函数名,以及参数访问一个结构的成员
.
结构体.成员名->
结构体指针->成员名//创建了一个结构体类型 - struct Stu struct Stu { //成员变量 char name[20]; int age; char id[20]; } int main() { int a = 10; //使用struct Stu这个类型创建了一个学生对象s1,并初始化 struct Stu s1={"张三", 20, "20241011"}; struct Stu* ps = &s1; printf("%s\n",s1.name); struct Stu* ps = &s1; printf("%s\n",(*ps).name); printf("%s\n",ps->name);//指针指向了对象 return 0; }
表达式求值
表达式求值的顺序一部分是由操作符的优先级和结合性所决定的。
同样,在这个过程中可能会有类型的转换。
隐式类型转换
整型提升
为了获取整型类型的精度,表达式中的字符和短整型在使用之前被替换为普通整型,这种转换称为整型提升。
#include<stdio.h>
int main()
{
char a = 3;
//00000000000000000000000000000011
//00000011 - a
char b = 127;
//00000000000000000000000001111111
//01111111 - b
char c = a+b;
//a和b相加
//00000000000000000000000000000011
//00000000000000000000000001111111
//00000000000000000000000010000010
printf("%d\n",c);//-126
//10000010 - c
//11111111111111111111111110000010 - 补码
//00000000000000000000000001111110 - 原码
return 0;
}
如何进行整型提升
按照变量的数据类型的符号位来进行提升
即 高位补充符号位
无符号数直接补0
实例1
#include<stdio.h>
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
a==0xb6?printf("a"):1;
b==0xb600?printf("b"):1;
c==0xb6000000?printf("c"):1;
return 0;
}
//只会打印c
//报出警告 warning: comparison is always false due to limited range of data type
实例2
#include<stdio.h>
int main()
{
char c =1;
printf("%u\n",sizeof(c));//1
printf("%u\n",sizeof(+c));//4
printf("%u\n",sizeof(!c));//1
return 0;
}
c只要参与了表达式运算,就会发生整型提升
算术转换
两个不同类型的数据进行计算时,要合理转换
操作符的属性
复杂表达式的求值一般有三个影响因素
操作符的优先级
操作符的结合性
从左到右还是从右到左
是否控制求值顺序
有
&&
,||
,?:
等
一些问题表达式
a*b+c*d+e*f
不能保证第三个
*
,一定比第一个+
早执行
c+ --c
,
–
的优先级高于+
我们无法得知+操作符的左操作数的获取是在右操作数之前还是之后,有歧义
非法表达式-1
int main() { int i = 10; i = i-- - --i * ( i = -3 )*i++ + ++i; printf("%d\n",i); return 0; }
这个表达式在不同的编译器中有不同的输出结果
非法表达式-2
int fun() { static int count = 1; return ++count; } int main() { int answer; answer = fun() - fun() * fun(); printf("%d\n", answer); return 0; }
不能确定调用的时间