操作符,也称运算符。是对数据进行操作处理的符号。
操作符有很多,常见操作符有:单目操作符、算数操作符、移位操作符、位操作符、赋值操作符、关系操作符、逻辑操作符、条件操作符、逗号表达式、下标引用、函数调用和结构体成员。
目录
单目操作符:
- 此分类方法是按照操作数(操作对象)的数量来分类的。
- 操作对象为一个的操作符,被称为单目操作符。
- 操作对象为多个的操作符,被称为多目操作符。(包括双目操作符、三目操作符)
常见单目操作符有:
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
逻辑反操作 ( ! )
这个操作符会将操作数的真假进行转换。C语言中,非0的数字都是真,只有数字0是假。
逻辑反操作符号其实就是将非0的数字(也就是除0之外的所有数字)转化为0;将数字0转化为1。
补充内容:布尔类型
C99中引入的概念,所谓布尔类型就是用来表示真假的类型。
如果想要创建布尔类型的变量,首先引用stdbool.h文件:
布尔类型不仅仅可以在定义数据类型时用到,还在函数返回值可以用到。
关于布尔类型的定义:(vs)
正负值( + - )
这个可以理解为正负号。(或者说,是改变原变量正负的符号。)
取地址(&)
顾名思义,它的操作就是将地址取出来。不过,一般情况下都是和赋值操作符一起用,创建一个变量然后把某个变量的地址取出来存里面。
sizeof()
这是用来计算某些变量所占内存空间的大小。(单位是字节)
规定sizeof计算的参数是无符号整型,因此在计算变量的大小时,会整型调整。(将整型变为无符号整型)。
sizeof的返回类型也是无符号整型。
size_t 叫无符号整型。(size_t --->unsigned int )
按位取反(~)
很好理解,将一个数的二进制位中,0变1,1变0。
++、--(分为前置和后置)
++和--的用法是一样的,所以就只举++的例子了。
int main()
{
int a = 4;
int b = 4;
printf("%d\n", ++a);
printf("%d\n", b++);
return 0;
}
这里的++a就是前置++,程序先执行a自增1的操作,再执行 printf 的操作。
这里的b++就是后置++,程序先执行 printf 的操作,再执行a自增1的操作。
总的来说,前置就是先改变变量本身,再让变量参与运算。后置就是先参与运算,再改变变量本身。 (加号在前就先加,加号在后就后加)
间接访问操作符( * )
也叫解引用操作符,是用来通过指针访问变量的。
变量b就是一个指针,通过解引用b,我们就可以对变量a进行操作。(这里的操作,可以是赋值、访问)
(类型)——强制类型转换
强制类型转换是把变量从一个类型转换为另一种类型。
算术操作符:
+ | - | * | / | % |
- 算数操作符,顾名思义,进行算术操作的符号。(这些符号都是双目操作符)
- 以上表格中的操作符,自左向右依次是加、减、乘、除、取模。
- 前四个我们都不陌生,而最后一个取模号,很多人都不太了解。其实取模很好理解,就是取余数。
- %操作符的两个操作数(操作对象)必须为整数,该符号返回的是整除后的余数。
- 除了%外,其他操作符都可以作用于整数和浮点数。(只要有浮点数参与,结果就会是浮点数;操作数里面全为整数,结果就只能是整数。)
关于算数操作符在使用的时候,也有一些细节需要注意的:
我们知道,数据有很多种类型,那么对两个不同类型的数据使用算术操作符,计算机是如何处理的呢? 结果又会是怎样的呢?
在这里,不得不提到一个名词 “隐式类型转换” 。当给计算机一些数据,让它对这些数据进行算术运算的时候,因为数据类型都不一样,所以正常来说两类型的数据是无法交流的。不过设计编译器的人已经考虑过会出现这样的问题,所以在设计编译器的时候,设计出了让它能自己将不同类型的数据转化为相同类型的数据后计算的功能。而这种转换是偷偷进行的,因此叫做 “隐式类型转换” 。
隐式类型转换分为两种:算术转换和整型提升
算术转换:
数据类型 | 字节数 |
long double | 16 |
double | 8 |
float | 4 |
unsigned long int | 4 |
long int | 4 |
unsigned int | 4 |
int | 4 |
以上表格中的数据类型,如果是不同类型之间使用除%之外的算术操作符,在运算的时候,会将其中一个操作数转化为另一个操作数的类型。
到底是谁转化谁?也是作了规定的。比较两个操作数的类型在上面表格中的排名,将排名低的转化为排名高的。
关于算术转换,还有一个小细节:
float f=3.14;
int num=f;//隐式转换,会有精度丢失。
整型提升:
- 首先,整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
通用CPU (general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
- 那些类型会被整型提升呢?
char、short int这些比int小的类型会被整型提升。
- 如何进行整形提升?
整型提升其实是按照变量的二进制符号位来提升(补位)的。(注意,整型提升的操作对象都是补码,也就说,操作的是内存中的二进制。)
对于无符号整型和有符号整型(正数和负数):(short、char、unsigned short、unsigned char)
有符号整型:(正数和负数)将其二进制位补充成32位。补充内容为该变量的符号位,(正数补0,负数补1)补充位置是高位。(所谓往高位上补,其实就是在补码前面补。)
无符号整型:无符号整型高位补充的是0。
移位操作符:
<< 左移操作符
>> 右移操作符
首先,我们需要知道的是它们是单目操作符。
(注意:位操作符的操作数只能是整数,并且在操作的的时候,操作的对象是二进制补码)
左移操作符:
它的规则只有一种:左边(高位)删除,右边(低位)补0。
对一个数字进行左移一位,有乘2的效果。
右移操作符:
分为算数右移和逻辑右移。
算数右移:规则是右边(低位)删除,左边(高位)补符号位。
逻辑右移:规则是右边(低位)删除,左边(高位)补0。
通过上面可以看到,算术右移和逻辑右移的操作本质上只是补位的时候有差别。
移位操作符在使用的时候,不可以移动负数位,也不可以移动数字超过32。
位操作符
位操作符有:
&——按位与
| ——按位或
^——按位异或
首先,我们需要知道的是它们是双目操作符。
(注意:位操作符的操作数必须是整数,并且在操作的的时候,操作的对象是二进制补码)
按位与(&)
该符号的规则是:两个数字对应的二进制位上,只要有0,就是0;同时为1,才是1。
下面是按位与的一个真实例子:
按位或(|)
该符号的规则是:两个数字对应的二进制位上,只要有1,就是1;同时为0,才是0。
下面是按位或的一个真实例子:
按位异或(^)
该符号的规则是:两个数字对应的二进制位上,相同为0,相异为1。
下面是按位异或的一个真实例子:
按位异或(^)还有个非常灵活的用法:
不创建临时变量,交换数字。
#include<stdio.h>
int main()
{
int a=3;
int b=-5;
printf("交换前:%d %d",a,b);
a=a^b;
b=a^b;
a=a^b;
printf("交换后:%d %d",a,b);
return 0;
}
按位异或(^)的特点:
- a^a=0; 0^a=a;(两个相等的数字亦或,结果是0。)
- 如果a^b=c,那么c^a=b;c^b=a;
- 异或操作符支持交换律
异或操作符交换两个变量:
- 可读性差
- 效率也不高,不如创建临时变量的方法。
- 亦或只能对整数进行交换。
赋值操作符
赋值操作符可以用来给变量重新赋值。
= 赋值操作符
除了普通的 “ = ” ,其实还有其他赋值操作符。
下面这些也是赋值操作符,不过它们叫做 “ 复合赋值符 ” 。
+=
-=
*=
/=
%=
<<=
>>=
&=
|=
^=
这些操作符都有复合的效果。
举个例子:
int x=10;
x=x+10;
上面两行代码还可以写成:
int x=10;
x+=10;
这样写的好处是:更加简洁。