首页 > 其他分享 >【C语言】操作符详解(一)

【C语言】操作符详解(一)

时间:2023-08-06 13:31:58浏览次数:37  
标签:右移 count return int 补码 C语言 详解 操作符 main

1.原码,反码,补码

int a=1;

整形占用四个字节----32bit

00000000 00000000 00000000 00000001  (数值位)

1.1原码,反码,补码的介绍

  • 整数的2进制表示方法有三种,即原码,反码,补码
  • 三种表⽰⽅法均有符号位和数值位两部分,符号位都是⽤0表⽰“正”,⽤1表⽰“负”,⽽数值位最⾼位的⼀位是被当做符号位,剩余的都是数值位。
  • 正整数的原,反,补码都相同
  • 负整数的三种表示方法各不相同
  1. 原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
  2. 反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
  3. 补码:反码+1就得到补码。

【C语言】操作符详解(一)_C语言

  • 原码和补码的相互转换均为:先取反,后+1.

1.2补码的作用

  • 对于整形来说:数据存放内存中其实存放的是补码。

为什么?

1. 在计算机系统中,数值⼀律⽤补码来表⽰和存储。原因在于,使⽤补码,可以将符号位和数值域统⼀ 处理;

2. 同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是 相同的,不需要额外的硬件电路。例如1-1可以转化为1+(-1)

#include <stdio.h>

//int main()
//{
//	int a = 5;
//	//00000000000000000000000000000101 - 原码
//	//00000000000000000000000000000101 - 反码
//	//00000000000000000000000000000101 - 补码
//
//	int b = -5;
//	//10000000000000000000000000000101 - 原码
//	//11111111111111111111111111111010 - 反码
//	//1111 1111 1111 1111 1111 1111 1111 1011 - 补码
//	//f    f    f    f    f     f    f   b
//	//0x ff ff ff fb   --->内存中的形式
//	return 0;
//}

另外在计算时补码符合计数规律

int main()
//{
//	//1-1
//	//1+(-1) = 0
//	//00000000000000000000000000000001
//	//10000000000000000000000000000001   
//	//10000000000000000000000000000010--> -2		原码相加之和
//	//
//	//00000000000000000000000000000001   1的补码
//	//11111111111111111111111111111111   -1的补码
//	//00000000000000000000000000000000		加1之后符号位的1到了第33位,消掉。补码相加之和
//由此可见补码相加才是正确的答案
//	//11111111111111111111111111111111
//	//10000000000000000000000000000000
//	//10000000000000000000000000000001
//	return 0;
//}

2.位移操作符

  • <<左移操作符
  • >>右移操作符
  • 注:移位操作符的操作数只能是整数。

2.1左移操作符

  • 移位规则:左边抛弃、右边补0

【C语言】操作符详解(一)_操作符_02

例如:

//int main()
//{
//	int a = -10;
//	int b = a << 1;
//	//10000000000000000000000000001010
//	//11111111111111111111111111110101
//	//11111111111111111111111111110110
//	//a<<1
//	//11111111111111111111111111101100
//	//10000000000000000000000000010011
//	//10000000000000000000000000010100
//	//-20
//	printf("b = %d\n", b);
//
//	return 0;
//}

2.2右移操作符

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

1.逻辑右移:左边⽤0填充,右边丢弃

2.算术右移:左边⽤原该值的符号位填充,右边丢弃

【C语言】操作符详解(一)_C语言_03

【C语言】操作符详解(一)_补码_04

举例如下:

//int main()
//{
//	int num = -1;
//	//10000000000000000000000000000001
//	//11111111111111111111111111111110
//	//11111111111111111111111111111111
//	//
//	int n = num >> 1;
//	printf("%d\n", n);
//
//	return 0;
//}结果仍为-1

警告⚠⚠:对于移位运算符,不要移动负数位,这个是标准未定义的。

2.3逻辑右移与算术右移的区别

  • 逻辑右移就是不考虑符号位,右移一位,左边补零即可。 算术右移需要考虑符号位,右移一位,若符号位为1,就在左边补1,;否则,就补0。
  • 算术右移也可以进行有符号位的除法,右移n位就等于除2的n次方。 例如,8位二进制数11001101分别右移一位。

3.位操作符:&(与),|(或),^(异或),~(取反)

3.1&(与):按位与 -- 对应的二进制位,有0则为0,两个同时为1才是1

int main()
{
	int a=5;
  int b=-6;
  int c=a&b;
  //00000000000000000000000000000101	5的补码
  //11111111111111111111111111111010	6的补码
  //00000000000000000000000000000000	结果
  printf("%d",c);
  return 0;
}//最终结果为0

3.2|(或):按位或 -- 对应的二进制位上,有1则为1,两个同时为0才是0

int main()
{
	int a=5;
  int b=-6;
  int c=a&b;
  //00000000000000000000000000000101	5的补码
  //11111111111111111111111111111010	6的补码
  //11111111111111111111111111111111	结果
  printf("%d",c);
  return 0;
}//最终结果为-1

3.3^(异或):按位异或 -- 对应的二进制位上,相同为0(真),相异则为1(假)

int main()
{
	int a=5;
  int b=-6;
  int c=a&b;
  //00000000000000000000000000000101	5的补码
  //11111111111111111111111111111010	6的补码
  //11111111111111111111111111111111	结果
  printf("%d",c);
  return 0;
}//最终结果为-1

3.4~(取反):按位取反 -- 二进制位,0变1,1变0

int main()
{
	int n = 0;
  int a = ~n;
  //00000000000000000000000000000000
  //11111111111111111111111111111111
  //包括符号位全部取反
  printf("%d",a);
  return 0;
}因此a=-

3.5那这为操作符有什么具体作用呢?

  • 举例1(&)
//想知道数字21的二进制序列中的最低位是几
int main()
{
	int a=21;
  //a&1
  //00000000000000000000000000010101	21的补码
  //00000000000000000000000000000001
  //00000000000000000000000000000001	结果为1
  return 0;
}
//因此我们可以通过按位与的这种方式来确定具体的某一位是几
//例如如果我们想知道第5位是几时,只需要向右移动4位
//(a>>4)&1
即可
  • 举例2(^)(难点)
题:不创建临时变量(第三个变量),实现两个数的交换
int main()
{
	int a=3;
  int b=5;
  a=a+b;
  b=a-b;
  a=a-b;
  printf("%d %d",a,b);
  return 0;
}
//可是存在一个问题:范围溢出。即当a和b过大时会出现错误。
解决方法:
int main()
{
	int a=3;
  int b=5;
  a=a^b;
  b=a^b;
  a=a^b;
  printf("%d %d",a,b);
  return 0;
}//发现也能得出结果
  • 举例3(或,取反)
int main()
{
	//将a的二进制中的di5位改成1
  int a=13;
  //00000000000000000000000000001101
  //1<<4
  //00000000000000000000000000010000
  a = a | (1<<4);
  printf("a=%d",a);//a=29
  //将a的二进制中第5位改成0
  //00000000000000000000000000001101
  //11111111111111111111111111101111  ~(1<<4)
  a = a &~(1<<4);
  printf("a=%d",a);//a=13
  return 0;
}

结论:

  • 0^a=a     a^a=0      3 ^ 3 ^ 5=5,3 ^ 5 ^ 3=5.所以得出异或支持交换律
  • 这种异或操作是有局限性的:
  1. 只能作用于整数交换
  2. 代码可读性差
  3. 代码的执行效率也是低于设置3个参数的

3.6练习:编写代码实现:求一个整数储存在内存中的二进制中1的个数。

int main()
{
	int a = 15;
  //1 1 1 1
  //8 4 2 1
  //15%2 = 1
  //15/7 = 7
  //1 1 1
  //7%2 = 1
  int count=0;
  while(a)
  {
  	if(a%2 == =)
    {
    	count++;
    }
    a = a/2;
  }
  printf("count=%d",count);
  return 0;
}但是当你输入负数的时候,就会出现错误

//法二
int main()
{
	int a = 0;
	scanf("%d", &a);
	int i = 0;
	int count = 0;
	for (i = 0; i < 32; i++)
	{
		if (((a >> i) & 1) == 1)
		{
			count++;
		}
    }
	printf("%d\n", count);
	return 0;
}

//法三,mage进化
int main()
{
	int n = 0;
	scanf("%d", &n);
	int count = 0;
	while (n)
	{
		n = n & (n - 1);//每进行一次循环都会减去一个一
		count++;
	}
	printf("%d\n", count);

	return 0;
}


4.逗号表达式

exp1, exp2, exp3, …expN
  • 逗号表达式,就是⽤逗号隔开的多个表达式。
  • 逗号表达式,从左向右依次执⾏。整个表达式的结果是最后⼀个表达式的结果。

举例:

//代码1 

int a = 1;

int b = 2;

int c = (a>b, a=b+10, a, b=a+1);//逗号表达式 
c为13

//代码2 

if (a =b + 1, c=a / 2, d > 0)

//代码3 
a = get_val();
count_val(a);

while (a > 0)
{
 //业务处理 
 a = get_val();
 count_val(a);
}

如果使⽤逗号表达式,改写:

while (a = get_val(), count_val(a), a>0)
{
 //业务处理 
}












标签:右移,count,return,int,补码,C语言,详解,操作符,main
From: https://blog.51cto.com/u_16189938/6983530

相关文章

  • 前端学习笔记202307学习笔记第六十一天-Dart的数据类型详解7
        ......
  • (通俗易懂)可视化详解多通道 & 多通道输入输出卷积代码实现
    以前对多通道和多通道输入输出的卷积操作不理解,今天自己在草稿纸上画图推理了一遍,终于弄懂了。希望能帮助到大家。多通道可视化一通道的2x2矩阵torch.Size([2,2])相当于torch.Size([1,2,2]),是一通道的2x2矩阵二通道的2x2矩阵torch.Size([2,2,2])代表二通道的2x2矩阵,第一个2表......
  • Pandas 的Merge函数详解
    在日常工作中,我们可能会从多个数据集中获取数据,并且希望合并两个或多个不同的数据集。这时就可以使用Pandas包中的Merge函数。在本文中,我们将介绍用于合并数据的三个函数merge、merge_ordered、merge_asof https://avoid.overfit.cn/post/9928a4b397734cfcb4aea5a2......
  • Vue进阶(幺肆贰):CSS-静态定位,相对定位,绝对定位,固定定位的用法和区别详解
    (文章目录)一、前言CSS提供了三种基本的定位机制:普通流、浮动和固定定位;通过这三种方式可实现页面的排版布局。二、普通流普通流中元素的位置由元素在(X)HTML中的位置决定:块级元素独自占一行,在文本流中从上到下一个接一个地排列;行内元素在一行中并排排列,遇到父元素的......
  • C语言分支与循环(18) --- 编写一个关机程序
    一.编写一个程序,要求程序运行后电脑一分钟内自动关机,若用户输入:no则取消关机示例代码:#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>#include<windows.h>intmain(void){ printf("您的电脑将在一分钟内关机,若需要取消关机请输入no\n"); system("shutdown-s-t60");R......
  • 我的第十一次C语言练习
    #definePI3.14159//intmain(void)//{// intnumber=7;// floatpies=12.75;// intcost=7800;// printf("The%dcontestantsate%fberrypies.\n",number,pies);// printf("Thevalueofpiis%f.\n",PI);// printf("Fare......
  • 基数排序详解
    基数排序详解1)前言:计数排序要学基数排序,掌握计数排序非常重要。计数排序的原理十分的简单。举个例子,排序52413,你打算怎么办?很简单是不是,冒泡排序、选择排序、归并排序……这些都足以解决。但如果你有100000000个数要排序,你可能就要束手就擒了。那如归这时候我告诉你:这1000......
  • Docker网络详解
    Docker是一种轻量级容器化技术,允许通过隔离OS级的虚拟化方式在一个操作系统上运行多个应用。网络是Docker中的一个非常重要的组件,它允许容器之间进行通信和联网访问。本文介绍Docker网络的基础知识,包括网络类型、网络驱动程序和网络配置等方面。一、Docker网络概述Docker网络有......
  • linux select函数详解
    转载:linuxselect函数详解-AlanTu-博客园(cnblogs.com)在Linux中,我们可以使用select函数实现I/O端口的复用,传递给 select函数的参数会告诉内核:     •我们所关心的文件描述符     •对每个描述符,我们所关心的状态。(我们是要想从一个文件描述符中读或者写,还......
  • C语言编程工具软件推荐!
    1、VS(VisualStudio)[VS是目前最受欢迎的适用于Windows平台应用程序的综合开发环境,由于大多数同学使用的都是Windows操作系统,因此VS非常适合大家。在日常课堂和考试中,我们使用的VS2010支持多种不同的编程语言,VS2010最初支持的语言包括:VisualBasic、VisualC#、VisualC++、Vis......