【C语言】常用的操作符以及类型转换(隐式和显式转换)

一、介绍内容

操作符和操作数:如表达式3+2,+是操作符,+左右的3和2是操作数。 下面介绍几个相对麻烦的操作符

  • 移位操作符:左移和右移操作符的区别
  • 位操作符:按位与、按位或、按位异或
  • 单目操作符:几个需要注意的单目操作符
  • 逻辑操作符:逻辑操作符所带来的语句结束

而在表达式中求值中,关注

  1. 隐式类型转换和显式类型转换对表达式值的影响
  2. 表达式中的优先顺序
  3. 介绍一些错误表达式写法产生的不唯一值。

二、操作符详解

1.移位操作符

在这里插入图片描述
操作符的操作数必须是整数,也不能是负数

先来看看什么是原码、反码、补码
在这里插入图片描述

左移操作符:
补码向左移动一位,右边补一位0。
在这里插入图片描述
右移操作符:
右移运算分为两种:
  1.逻辑移位:左边用0填充,右边丢弃
  2.算术移位:左边用原符号位填补,右边丢弃(大多数情况都是)
在这里插入图片描述

int main()
{

	int a = 7;
	int b1 = a >> 1;
	int b2 = a << 1;
	printf("%d\n", a);//7
	printf("%d\n", b1);//3
	printf("%d\n", b2);//14

	int c = -7;
	int d1 = -7 >> 1;
	int d2 = -7 << 1;
	printf("%d\n", c);//-7
	printf("%d\n", d1);//-4
	printf("%d\n", d2);//-14
}

2.位操作符

  • & 按位与( & 左右操作数有0就为0,只有1 & 1才为1)
  • |  按位或( | 左右操作数有1就为1,只有0 | 0才为0)
  • ^ 按位异或( ^ 左右操作数相等如1 ^ 1就为0,左右不相等如1 ^ 0就为1)
  • 注:他们的操作数必须是整数。

在这里插入图片描述

并且通过以下代码,可得到结论:

  1. 相同数异或得0
  2. 一个数异或2次同一个数,会等于它本身,0和一个数异或会等于数本身

    在这里插入图片描述
    所以或许可以通过异或交换两个变量
#include <stdio.h>
int main()
{
 int a = 10;
 int b = 20;
 a = a^b; 
 b = a^b; //b=a^b^b 为原来a的值
 a = a^b; //a=a^a^b 为原来b的值
 printf("a = %d b = %d\n", a, b); //a=20 b=10
 return 0;
}

3.单目操作符

先来看看sizeof 操作符,sizeof可能会被认为是一个函数,但下方sizeof a去括号的时候也能得到值,这说明sizeof是一个操作符,并且可以注意一下sizeof返回值实际是无符号整型(unsigned int)。
在这里插入图片描述
下面来看看取反操作符 ~

在这里插入图片描述

4.逻辑操作符

&&  逻辑与
||   逻辑或

因为在&&中操作数有0结果一定就为0
在这里插入图片描述
因为在 || 中操作数有非0结果一定非0
在这里插入图片描述

三、表达式求值中的问题

1.隐式类型转换

C的整型算术运算总是至少以默认整型类型的精度来进行的

也就是精度较小的char或short类型,在进行表达式运算,需要转换成至少int类型的精度来进行计算。
下面来看这个代码

int main()
{
	char c1 = 5;
	char c2 = 126;
	//00000000 00000000 00000000 00000101 c1
	//00000101  char类型一个字节的取断 c1
	//00000000 00000000 00000000 01111110 c2
	//01111110  c2

	//c3=10000011  c1+c2 整型提升的时候补的是符号位1
	//11111111 11111111 11111111 10000011 补码
	//11111111 11111111 11111111 10000010 反码
	//10000000 00000000 00000000 01111101 //-125

	char c3 = c1 + c2;
	printf("%d\n", c3); //-125
	return 0;
}

还有一个例子
+c和-c,使得c整型提升为4个字节
当然sizeof不加括号也是可以的。

int main()
{
 char c = 1;
 printf("%u\n", sizeof(c));//1
 printf("%u\n", sizeof(+c));//4
 printf("%u\n", sizeof(-c));//4
 return 0;
}


2.显式类型转换

在大于等于int类型精度的其它类型中,例如有以下层次体系:

  • long double
  • double
  • float
  • unsigned long int
  • long int
  • unsigned int
  • int

如果一个float和一个int类型进行计算的话,最终结果将返回一个float类型。
如果一个float和一个double类型进行计算的话,最终结果将返回一个double类型。

来看下面这个程序,对未初始化的全局变量初始值是0,那么i–的话是-1,又sizeof(i)返回的
类型是unsigned int 类型,int和unsigned int 类型比较会将-1提升至对应的无符号整型,这个数非常大,所以结果是>。

#include <stdio.h>
int i;
int main()
{
    i--;
    if (i > sizeof(i))
    {
        printf(">\n");
    }
    else
    {
        printf("<\n");
    }
    return 0; 
}


3.问题表达式

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

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

如果两个相邻的操作符优先级相同,取决于它们的结合性(结合性就是从左到右顺序,还是从右到左的顺序)。

是否控制求值顺序:例如三目运算符? :,控制True和False情况的取值。


那么通过这三个影响因素是否能确定表达式唯一的值呢?答案是不一定
下面来看看几个表达式
表达式1:

c + --c;

操作符优先级只能决定- -的运算在+的前面,但是并不能知道,先确定c的值,还是先- -c再确定c的值,是有歧义的。

表达式2:

#include <stdio.h>
int main()
{
 int i = 1;
 int ret = (++i) + (++i) + (++i);
 printf("%d\n", ret);
 printf("%d\n", i);
 return 0;
}

第一种算法:先经过三次++i后,i=4,再进行加法,最后得12。
第二种算法:先经过前两次++i后,i=3,再进行第一个加法得6,再进行剩下的++i,i=4,最后得10

以上两种结果分别是vs和linux环境下的结果。

总结:如果不能通过操作符的三个属性确定唯一的计算结果,那么这个表达式就是有问题的,但一般人都不会这样写代码,所以也需要避免这样写,以免有歧义。


本章完~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值