C语言操作符超详细讲解上篇

目录
  • 前言
  • 1、操作符的分类
  • 2、算术操作符
  • 3、移位操作符
    • 3.1 左移操作符
      • 3.1.1 正数左移1位
      • 3.1.2 负数左移1位
    • 3.2 右移操作符
      • 3.2.1 正数右移1位
      • 3.2.2 负数右移1位
    • 3.3 移位操作符说明
  • 4、位操作符
    • 4.1 练习 1
    • 4.2 练习 2
  • 总结

前言

操作符主要内容包括:各种操作符的介绍,用表达式求值。

1、操作符的分类

  • 算术操作符
  • 移位操作符
  • 位操作符
  • 赋值操作符
  • 单目操作符
  • 关系操作符
  • 逻辑操作符
  • 条件操作符
  • 逗号表达式
  • 下标引用、函数调用和结构成员

2、算术操作符

 +  -  *  /  %  (加法 减法 乘法 取余 取模)
int main()
{
	int a = 9 / 2;//4
	float b = 9 / 2;
	int c = 9.0 / 2;
	float d = 9.0 / 2;//4.5
	float e = (float)9.0 / 2;

	printf("%d\n", a);
	printf("%f\n", b);
	printf("%d\n", c);
	printf("%f\n", d);
	printf("%f\n", e);
	return 0;
}

运行结果见下图:

通过例子可发现,变量的类型使用错误的话,结果也是错误的

  • 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数
  • 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法
  • % 操作符的两个操作数必须为整数。返回的是整除之后的余数

3、移位操作符

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

<< 左移操作符
>> 右移操作符

3.1 左移操作符

  • 移位规则:左边抛弃、右边补0
  • 整数是 int 型,占4个字节,有32位表示。其中最高位表示符号,0为正,1为负
  • 整数在内存中存储的是补码的二进制,正数的原码、反码、补码是相同的
  • 操作符对整数操作的流程:

(1)先将整数的原码转换成反码

(2)反码 +1转换成补码

(3)最后对整数的补码进行操作

(4)操作结束后,将操作后的补码 -1 转换成反码

(5)将反码转换成最终的原码

  • 函数printf打印的是整数的原码

3.1.1 正数左移1位

代码如下(示例):

int main()
{
	int a = 5;
	int b = a << 1;//操作的补码二进制位,a本身结果不变
	printf("%d\n", a);//打印5
	printf("%d\n", b);// -10
	return 0;
}

结果运行见下图,与分析的结果一致,左移1位的效果相当于乘以2,左移在51单片机、STM32中,操作寄存器会经常用到。

3.1.2 负数左移1位

int main()
{
	int a = -5;
	int b = a << 1;//<< >> 操作的二进制位
	printf("%d\n", a);//打印-5
	printf("%d\n", b);// -10
	return 0;
}

运行结果见下图,和分析的结果一致

3.2 右移操作符

右移移位规则运算分两种:

  • 逻辑移位:左边用0填充,右边丢弃
  • 算术移位:左边用原该值的符号位填充,右边丢弃

3.2.1 正数右移1位

int main()
{
	int a = 5;
	int b = a >> 1;//右移不一定是除2

	printf("%d\n", a);//打印-5
	printf("%d\n", b);// -3
	return 0;
}

下面分析右移的过程:正数的原码、反码、补码一样

00000000 00000000 00000000 00000101 //5的二进制补码
//算术右移:左边用原该值的符号位1填充,右边丢弃1
00000000 00000000 00000000 00000010 //右移后的补码
//右移后的补码就是右移后的原码  2

结果见下图:

3.2.2 负数右移1位

int main()
{
	int a = -5;
	int b = a >> 1;//右移不一定是除2

	printf("%d\n", a);//打印-5
	printf("%d\n", b);// -3
	return 0;
}

下面分析右移的过程:

10000000 00000000 00000000 00000101 //-5的二进制原码
11111111 11111111 11111111 11111010 //反码
11111111 11111111 11111111 11111011 //补码:反码+1
//算术右移:左边用原该值的符号位1填充,右边丢弃1
11111111 11111111 11111111 11111101 //右移后的补码
11111111 11111111 11111111 11111100 //反码:补码-1
10000000 00000000 00000000 00000011 //原码  -3

结果见下图:

3.3 移位操作符说明

注意事项:

  • 右移操作符采用逻辑移位还是算术移位,取决于电脑编译器,我的是算术移位,所以举例以算术移位分析的,逻辑移位分析流程一样
  • 对于移位运算符,不要移动负数位,这个是标准未定义的,例如:
int num = 10;
num>>-1;//10右移-1位,这是错误的表达

4、位操作符

位操作符有:

& //按位与     相同为1, 相异为0
| //按位或     有1为1, 全0为0
^ //按位异或    相同为0, 相异为1
//注:他们的操作数必须是整数

int main()
{
	int a = 3;
	int b = -5;
	int c = a & b;
	int d = a | b;
	int e = a ^ b;//异或
	//对应的二进制位:相同位0,相异为1
	printf("%d\n", c);// 打印3
	printf("%d\n", d);// -5
	printfan("%d\n", e);// -8
	return 0;
}

00000000 00000000 00000000 00000011   3的补码
11111111 11111111 11111111 11111011   -5的补码
//按位与:  相同为1, 相异为0
00000000 00000000 00000000 00000011    3的补码,原码表示3
//按位或:   有1为1, 全0为0
11111111 11111111 11111111 11111011   -5的补码,原码表示-5
//按位异或: 相同为0, 相异为1
11111111 11111111 11111111 11111000  补码
11111111 11111111 11111111 11110111  反码
10000000 00000000 00000000 00001000  原码 -8

输出结果见下图,与分析一致:

4.1 练习 1

不能创建临时变量(第三个变量),实现两个数的交换

int main()
{
	int a = 3;
	int b = 5;

	printf("a=%d b=%d\n", a, b);
	//第一种,常用的方法,创建中间变量
	int tmp = a;
	a = b;
	b = tmp;
	//第二种,不创建变量
	a = a + b;
	b = a - b;
	a = a - b;
	//第三种,不创建变量,很难想到
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("a=%d b=%d\n", a, b);
	return 0;
}

4.2 练习 2

求一个整数存储在内存中的二进制中1的个数

//举例: 5   &1, 然后右移1位, 再&1
//00000000 00000000 00000000 00000101
//00000000 00000000 00000000 00000001

int main()
{
	int num = 0;
	scanf("%d", &num);
	int i = 0;
	int cnt = 0;
	//位操作
	for ( i = 0; i < 32; i++)
	{//每次右移一位就 &1
		if (1==((num>>i)&1))
		{
			cnt++;//所有位与1,相同为1,相异为0
		}
	}
	printf("%d", cnt);
	return 0;
}

总结

本文对部分操作符进行了,介绍,也分析了操作符的具体实现过程,这里了解原理即可,具体运算交给计算机执行,没必要每个都自己画图分析,耗时,不细心可能还会出错,32位二进制建议大家划分成4个字节,8位一组,好看一些,这在STM32 单片机对寄存器操作时,经常这样划分,一目了然。

到此这篇关于C语言操作符超详细讲解上篇的文章就介绍到这了,更多相关C语言 操作符内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言操作符进阶教程(表达式求值隐式类型转换方法)

    目录 结构体 表达式求值 隐式类型转换 意义: 方法 算术转换 操作符属性 结构体 结构体变量的声明需要在主函数之上或者主函数中声明,如果在主函数之下则会报错,而且c语言中的结构体不能直接进行强制转换,只有结构体指针才能进行强制转换. 涉及结构体的操作符这里讲两个:. (结构体访问操作符)-> () 首先写一段代码: int main() { struct Stu s = {"me",19,60}; prinft("%s %d %lf",s.who,s.age

  • C语言各种操作符透彻理解上篇

    前言:在我们程序编写领域,操作符给我们提供了很多的运算便利,但操作符琳琅满目,我们要怎样用好它们呢,下面就带你来熟悉熟悉这些多样的操作符. 操作符分类: 算术操作符 .移位操作符 .位操作符 .赋值操作符 .单目操作符 .关系操作符 .逻辑操作符 .条件操作符 .逗号表达式 .下标引用.函数调用和结构成员 1.算数操作符(+.--.*.%./) 这里我们着重讲一下取余(模)%操作符和除法/操作符 #include<stdio.h> int main() { //取余(模).除法 int ret

  • 一篇文章带你入门C语言:操作符

    目录 操作符 分类 算术操作符 移位操作符 整数存储规则 左右移位规则 赋值操作符 单目操作符 取地址操作符& 解引用操作符* 类型长度操作符sizeof 按位取反操作符~ ++ -- 操作符 强制类型转换操作符(type) 关系操作符= 逻辑操作符 短路运算 条件操作符 逗号表达式 下标引用.函数调用和结构成员 下标引用操作符[] 函数调用操作符() 结构成员操作符. -> 结构体定义 结构体使用 结构体地址 表达式求值 隐式类型转换 整型提升 如何整型提升 有符号数 无符号数 算术转换

  • C语言操作符基础知识详解

    目录 一.单目操作符: 二.关系操作符 三.条件操作符 四.逗号表达式 五.逻辑操作符 总结 一.单目操作符: !:逻辑反操作符: -:负数操作符: +:整数操作符: &:取地址操作符: sizeof:操作数的类型长度操作符: sizeof(数组名)--数组名表示整个数组,sizeof(数组名)求的是整个数组的大小,单位是字节 例如: int a[10] = { 0 }; printf("%d\n",sizeof(a)); suzeof(a[0]);-->(4) 不同的表

  • 详解C语言之操作符

    目录 1.加减乘 2.除(/) 注意: 3.取余(%) 注意: 4.移位操作符(>> <<) 注意 5.位操作符(| ,& ,^) 6.逻辑操作符(&& , ||) 7.单目操作符 7.1正负号(+ -) 7.2sizeof() 7.3按位取反(~) 7.4逻辑反操作(!) 8.赋值操作符 9.复合操作符.等式左边不是常量 补充: 总结 1.加减乘 c里的加减乘同我们实际生活功能相同,我们不做探究,看例子即可 2.除(/) c语言里的除法实质上是求商操作(零

  • C语言各种操作符透彻理解下篇

    1.单目操作符 之前有了解到的三目操作符(?:),指的是有三个操作数 例如:3+5 其中,+是一个操作符 3是左操作数 5是有操作数 +则是一个双目操作符 那么什么是单目操作符呢,也就是只有一个操作数的 我们常见的操作符有:  这里我们来详细介绍一下sizeof.~.++与-- 1.sizeof sizeof常用来计算类型的长度,比如数组类型,int.char.short等等.同时,sizeof是操作符,不是函数,所以后面的括号可以省略.但算类型长度的时候不能省,这是语法要求. 下面就是size

  • C语言 操作符分类解析与使用

    目录 操作符的分类 算术操作符 移位操作符 位操作符 逻辑操作符 逗号表达式 表达式求值 隐式类型转换 算术转换 操作符的属性 xwg今天就带各位大佬来了解一波C语言的操作符. 操作符的分类 常见的操作符分别如下: 算术操作符 移位操作符 位操作符 逻辑操作符 逗号表达式 算术操作符 算术操作符是我们最常用的操作符:+ - * / % 注: 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数. 对于 / 操作符如果两个操作数都为整数,执行整数除法,而只要有浮点数执行的就是浮点数除法.

  • C语言操作符超详细讲解上篇

    目录 前言 1.操作符的分类 2.算术操作符 3.移位操作符 3.1 左移操作符 3.1.1 正数左移1位 3.1.2 负数左移1位 3.2 右移操作符 3.2.1 正数右移1位 3.2.2 负数右移1位 3.3 移位操作符说明 4.位操作符 4.1 练习 1 4.2 练习 2 总结 前言 操作符主要内容包括:各种操作符的介绍,用表达式求值. 1.操作符的分类 算术操作符 移位操作符 位操作符 赋值操作符 单目操作符 关系操作符 逻辑操作符 条件操作符 逗号表达式 下标引用.函数调用和结构成员

  • C语言指针超详细讲解上篇

    目录 前言 1.指针是什么 1.1 指针变量 1.2 指针是内存中一个最小单元的编号 2.指针和指针类型 2.1 指针±类型 2.2 指针的解引用 2.2.1 int* 类型的解引用 2.2.2 char* 类型的解引用 3.野指针 3.1 野指针成因 3.1.1 指针未初始化 3.1.2 指针越界访问 3.1.3 指针指向的空间释放 3.2 如何规避野指针 总结 前言 本文开始指针相关内容的学习,主要内容包括: 指针是什么 指针和指针类型 野指针 指针运算 指针和数组 二级指针 指针数组 1.

  • C语言操作符超详细讲解下篇

    目录 前言 赋值操作符 单目操作符 单目操作符介绍 sizeof 和 数组 关系操作符 逻辑操作符 条件操作符 逗号表达式 下标引用与函数调用和结构成员 [ ] 下标引用操作符 ( ) 函数调用操作符 访问一个结构的成员 表达式求值 隐式类型转换-整形提升 算术转换 操作符的属性 总结 前言 本文接着学习操作符的内容. 赋值操作符 赋值操作符就是能够重新赋值 int weight = 120;//体重 weight = 89;//不满意就赋值 double salary = 10000.0; s

  • C语言函数超详细讲解上篇

    目录 前言 1.函数是什么? 2.C语言中函数的分类 2.1 库函数 2.1.1 如何学会使用库函数 2.1.2 自定义函数 3.函数的参数 3.1 实际参数(实参) 3.2 形式参数(形参) 4.函数的调用 4.1 传值调用 4.2 传址调用 4.3 练习 4.3.1 判断一个数是不是素数 4.3.2 判断一年是不是闰年 4.3.3 二分查找 4.3.4 数值自增增加1 5.函数的嵌套调用和链式访问 5.1 嵌套调用 5.2 链式访问 总结 前言 本文主要学习函数的相关内容. 1.函数是什么?

  • C语言数据的存储超详细讲解上篇

    目录 前言 1.数据类型介绍 类型的基本归类 2.整形在内存中的存储 2.1 原码.反码.补码 2.2 大小端介绍 2.2.1 什么是大小端 2.2.2 大端和小端意义 2.2.3 写程序判断字节序 总结 前言 本文开始学习C语言进阶的内容了,进阶内容,是在基础阶段的内容上进行拓展,有的知识点,在基础阶段也已经学过.在进阶内容中,将从更深层次的角度去理解学习,本文主要内容包括: 数据类型详细介绍 整形在内存中的存储:原码.反码.补码 大小端字节序介绍及判断 浮点型在内存中的存储解析 1.数据类型

  • C语言指针超详细讲解下篇

    目录 前言 指针运算 指针±整数 4.1 指针±整数 4.2 指针-指针 4.3 指针的关系运算 5.指针和数组 6.二级指针 7.指针数组 7.1 举例 1 7.2 举例 2 总结 前言 本文接着上一篇内容,继续学习指针相关知识点. 指针运算 指针±整数 指针-指针 指针的关系运算 4.1 指针±整数 #define VALUE 5 int main() { float values[VALUE]; float *vp; //指针+-指针,关系运算 for (vp = &values[0];

  • C语言数组超详细讲解下篇扫雷

    目录 前言 1.扫雷是什么? 2.程序框架 2.1 主函数 2.2 函数menu 2.3 函数game 2.3.1 函数init_board 2.3.2 函数show_board 2.3.3 函数set_mine 2.3.4 函数find_mine 2.3.5 函数get_mine_count 3.头文件.h 4.游戏试玩 总结 前言 本文接着复习前面所学知识,以扫雷游戏为例. 1.扫雷是什么? 百度百科:<扫雷>是一款大众类的益智小游戏,于1992年发行.游戏目标是在最短的时间内根据点击格子

  • C语言数组超详细讲解上

    目录 前言 1.一维数组的创建和初始化 1.1 一维数组的创建 1.2 一维数组的初始化 1.3 一维数组的使用 1.4 一维数组在内存中的存储 2.二维数组的创建和初始化 2.1 二维数组的创建 2.2 二维数组的初始化 2.3 二维数组的使用 2.4 二维数组在内存中的存储 3.数组越界 4.数组作为函数参数 4.1 冒泡排序函数的错误设计 4.2 数组名是什么? 4.3 对数组名的用法进行总结 4.4 冒泡排序函数的正确设计 总结 前言 本文主要介绍数组相关的内容,主要内容包括: 一维数组

  • C语言数据结构超详细讲解单向链表

    目录 1.链表概况 1.1 链表的概念及结构 1.2 链表的分类 2. 单向链表的实现 2.1 SList.h(头文件的汇总,函数的声明) 2.2 SList.c(函数的具体实现逻辑) 2.2.1 打印链表 2.2.2 搞出一个新节点(为其他函数服务) 2.2.3 链表尾插 2.2.4 链表头插 2.2.5 链表尾删 2.2.6 链表头删 2.2.7 查找节点 2.2.8 在pos位置之前插入 2.2.9 在pos位置之后插入 2.2.10 删除pos位置 2.2.11 删除pos之后位置 2.

  • C语言函数超详细讲解下篇

    目录 前言 函数的声明和定义 函数声明 函数定义 举例 简单的求和函数 把加法单独改写成函数 添加函数声明 带头文件和函数声明 静态库(.lib)的生成 静态库文件的使用方法 函数递归 什么是递归? 递归的两个必要条件 练习1 一般方法 递归的方法 练习2 一般方法 递归方法 练习3 一般方法 递归方法 练习4 一般方法 递归方法 递归与迭代 递归隐藏的问题 如何改进 选递归还是迭代 总结 前言 紧接上文,继续学习函数相关内容. 函数的声明和定义 函数声明 告诉编译器有一个函数叫什么,参数是什么

随机推荐