栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言操作符详解

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言操作符详解

目录

1.算数运算符:+ - * / %

2.移位操作符

(1)<<左移操作符

(2)>>右移操作符

算术移位:右边丢弃,左边补原符号位

逻辑移位:右边丢弃,左边补零

3.位操作符

(1)& - 按(二进制)位与

(2)| - 按(二进制)位或

(3)^ - 按(二进制)位异或

(4)用法

<1>位异或用法

<2>位与用法

<3>位或运算

4.赋值操作符:"="

复合赋值符+=,-=,*=,/=,%=,>>=,<<=,&=,|=,^=

5.单目操作符(只有一个操作数)

!,-,+,&,sizeof,~,--,++,*,(类型)

6.关系操作符:>,>=,<,<=,!=,==

7.逻辑操作符:&&(逻辑与),||(逻辑或)

8.条件(三目)操作符:exp1? exp2 : exp3

9.逗号表达式

10.下标引用,函数调用,和结构成员

(1)[ ] 下标引用操作符

(2)()函数调用操作符

(3)访问一个结构的成员

11.表达式求值

(1)隐式类型转换

(2)算术转换

(3)操作符的属性


1.算数运算符:+ - * / %
  • “/”操作符如果结果要得到浮点数,则至少有一个数应该是浮点数
  • “%”取模操作符的两端必须是整数,负数运算与实际运算结果也相同

2.移位操作符

警告:不要移动负数位,这是标准未定义型

例如:

a >> -1

移位操作符移的是补码二进制位,int型四个字节,所以32位二进制位

注:移位操作符的操作数只能是整数

(1)<<左移操作符

运算规则:向左移动,左边丢弃,右边补零

结果都是原来数的2^n倍,n即为位移量 ,负数向下取整

代码样例:

int a = 3; 
int b = a << 1;

a(补码) = 00000000000000000000000000000011

b(补码) = 00000000000000000000000000000110

输出:

由此可见,移位之后a不变,变化的结果赋值给b,值传递

(2)>>右移操作符

不同编译器采取的右移方式不同,但一般都是算术移位

算术移位:右边丢弃,左边补原符号位

结果是由原来的数除以2^n得到,正数向下取整,负数四舍五入

代码样例:

int a = 8; 
int b = a >> 2;

a(补码)= 00000000000000000000000000001000

b(补码)= 00000000000000000000000000000010

输出:

 a = 8,b = 2

逻辑移位:右边丢弃,左边补零

3.位操作符

        int型32位每一位都参与运算

(1)& - 按(二进制)位与

(2)| - 按(二进制)位或

(3)^ - 按(二进制)位异或

(4)用法

<1>位异或用法
  1. 不创建两个临时变量,实现两个数的交换

省一个变量,但开发中不常用,运行速度比定义一个变量实现交换要慢

int a = 3;
int b = 5;
a = a ^ b;
b = a ^ b;
a = a ^ b;

结果打印:

//交换前:a = 3,b = 5
//交换后:a = 5,b = 3

原理:位操作符满足交换律,a ^ a == 0,a ^ 0 = a;

b = a ^ b ^ b == a;

a = a ^ b ^ a == b;

<2>位与用法
  1. 求一个整数存储在内存中的二进制中1的个数(即求补码中的一的个数)

        (1)方法一

int a = 3;
int count = 0;
for(int i = 0; i < 32; i++){
	if(a & 1 == 1) count++;
	a >>= 1;
}

结果打印:

//a的补码中1的个数为2

原理:1的补码为00000000000000000000000000000001,1与其他数的位与运算都只与最后一位有关,若最后一位是0,则结果是0,否则是1,再利用右移操作符循环32次,依次判断每一位的数字

(2)方法二

int a = 3;
int count = 0;
while(a){
    a = a & a(a-1);
    count++;
}

结果打印:

原理:a & a-1得到的结果会让a的二进制位失去一个1,多次循环就可得到1的个数,不需要挨个判断

举例:11——1011

11-1——1010 11 & (11-1)== 1010

1010 - 1——1001 1010&1001 == 1000

1000 - 1——0111 1000&0111 == 0000

<3>位或运算
  1. 将一个数补码中的某一位赋值为1
int a = 10;		
//假设赋值的是第5位 
int count = 5;
int b = 1;
b <<= count - 1;
a = a | b;

结果打印:

//a的二进制为0000000A
//a的二进制为0000001A

原理:1的补码为00000000000000000000000000000001,1可通过左移操作符找到目标位置,此时与其他数的位或运算都只与目标位有关,此时目标位由于或运算被赋值为1

4.赋值操作符:"="

注意”=“与”==“的区别

赋值运算符可以连续使用,但一般不使用

a = b = 3;

复合赋值符+=,-=,*=,/=,%=,>>=,<<=,&=,|=,^=

5.单目操作符(只有一个操作数)

!,-,+,&,sizeof,~,--,++,*,(类型)
  • sizeof        操作符的类型长度(以字节为单位)

当在自定义函数地址传递时,sizeof只会计算指针的字节数,无论是数组指针,int型指针,char型指针,都一视同仁

使用形式:

sizeof(a);   //a为变量
sizeof(int); //数据类型
sizeof a;    //可以不加括号
//但sizeof int这种写法不允许
  • ~         对一个数的二进制按位取反(补码)

举例:将整数的补码中的某一位赋值为0

int a = 16;		
//假设赋值的是第5位 
int count = 5;
int b = 1;
b <<= count - 1;
a = a & ~b;

结果打印:

原理:与“将整数的补码中的某一位赋值为1”类似,但增加了一个~取反运算,且变为位与运算

  • *         间接访问操作符(解引用操作符,常用形式为*p)
  • (类型) 强制类型转换

6.关系操作符:>,>=,<,<=,!=,==
  1. 再强调一次,注意”=“与”==“的区别
  2. 字符串无法用“==”比较(这样比较的是两个字符串首字符的地址),可以用头文件下的strcmp库函数来比较

7.逻辑操作符:&&(逻辑与),||(逻辑或)

对“&&”而言,当操作符左边的表达式为0(假)时,不再判断之后的表达式

对“||”而言,当操作符左边的表达式为1(真)时,不再判断之后的表达式

8.条件(三目)操作符:exp1? exp2 : exp3

9.逗号表达式

exp1,exp2 , exp3...expn;

在整个表达式里从左向右依次计算

10.下标引用,函数调用,和结构成员

(1)[ ] 下标引用操作符

例:

int arr[10];
arr[9] = 10;

[ ]的两个操作数为arr和9,因此arr[9]也可写成9[arr](类似交换律),但一般不这样写

(2)()函数调用操作符

接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数,因此至少有一个操作数

(3)访问一个结构的成员
  1. “.” 结构体.成员名
  2. “->” 结构体指针->成员名

11.表达式求值

表达式求值的顺序一部分是由操作符的优先级和结合性决定的

同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型

(1)隐式类型转换

C的整型算数(再强调!char类型也是属于整型家族)运算总是至少以缺省(默认)整型类型的精度来进行的。

为了获得这个精度,表达式中的字符和短整型操作符在使用之前被转换为普通整型,这种转换称为整型提升

整型提升的意义:

  1. 表达式的整型运算要在CPU的相应运算寄存器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度
  2. 因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度
  3. 通用CPU是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算

整型提升是按照字符的符号位进行整型提升的

例如:

  • char类型的-1的八位(补码)表示为:11111111

        整型提升后前24位补符号位1变为11111111111111111111111111111111

  • char类型的1的八位(补码)表示为:00000001

        整型提升后前24位补符号位0变为00000000000000000000000000000001

  • unsigned char类型无符号位,前面全部补0,-1(此时不再存在负值,即使赋值-1,实际表示255)可表示为:

00000000000000000000000011111111

经历运算之后若赋值给char类型,结果被截断,取后八位

经典例题:

int main(){
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;
	if(a == 0xb6)
		printf("a");
	if(b == 0xb600)
		printf("b");
	if(c == 0xb6000000)
		printf("c");
    return 0;
}

运行结果:

C

原因:在判断是否相等运算中,只有int型的c不需要整型提升,类似的,定义a为char型,用sizeof(-a)计算字节数,会发现结果为4,原因就是发生了整型提升,但sizeof(a)结果为1

(2)算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算数转换(排名采用升序)

int

unsigned int

long int

unsigned long int

float

double

long double

但是算数转换要合理,不然会有一些潜在问题,比如精度丢失

(3)操作符的属性

复杂表达式的求值有三个影响因素:

  1. 操作符的优先级
  2. 操作符的结合性
  3. 是否控制求值顺序

两个相邻的操作符先执行哪个,取决于他们的优先级,如果两者的优先级相同,取决于他们的结合性。

必须注意!!!哪怕这三个影响因素能够完全灵活运用,但是仍然会出现无法确定它的唯一运算路径得到唯一结果,即问题表达式。不同编译器规定有所不同,因此日常写代码时应避免编写过于复杂且可能出现歧义的代码

暑期编程PK赛 得CSDN机械键盘等精美礼品!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1015211.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号