[C]基础8.详解操作符
- 博客主页:算法歌者
- 本篇专栏:[C]
- 您的支持,是我的创作动力。
文章目录
- 0、总结
- 1、操作符的分类
- 2、二进制和进制转换
- 2.1、2进制转10进制
- 2.2、10进制转2进制
- 2.3、2进制转8进制和16进制
- 3、原码、反码、补码
- 4、移位操作符
- 4.1 左移操作符
- 4.2 右移操作符
- 4.3 警告:不要移动负数位
- 5、位操作符
- 5.1 例1:观察位操作符
- 5.2 例2:不能创建临时变量(第三个变量),实现两个数的交换。
- 5.3 例3:求一个整数存储在内存中的二进制中1的个数。
- 5.4 例4:如何判断一个数是否是2的次方数?
- 5.5 例5:二进制位置0或者置1
- 6、逗号表达式
- 7、下标访问[]、函数调用()
- 8、结构成员访问操作符
- 9、操作符的属性:优先级、结合性
- 10、其他
- 10.1 整型提升
- 10.2 算术转换
0、总结

1、操作符的分类
- 算术操作符:
+、-、*、/、% - 移位操作符:
<<、>> - 位操作符:
&、|、^、~ - 赋值操作符:
=、+=、-=、*=、/=、%=、<<=、>>=、&=、|=、^= - 单目操作符:
!、++、--、&(取地址操作符)、*(解引用操作符)、+(正号操作符)、-(负号操作符)、~、sizeof、(类型) - 关系操作符:
>、>=、<、<=、==、!= - 逻辑操作符:
&&、|| - 条件操作符:
?: - 逗号表达式:
, - 下标引用:
[] - 函数调用:
() - 结构成员访问:
.、->
操作符中一些操作符和二进制有关系,需要先简单了解二进制和进制转换的知识。
2、二进制和进制转换
进制,是数值的不同表示形式。例如,数值15的各种进制的表示形式:
15的2进制: 1111
15的8进制: 17
15的10进制:15
15的16进制:F
观察10进制,得出规律如下:
- 10进制中满10进1。
- 10进制的数字每一位都是0~9的数字组成。
那么,二进制也是一样的:
- 2进制中满2进1。
- 2进制的数字每一位都是0~1的数字组成。
2.1、2进制转10进制
在10进制中,每一位是权重,10进制的数字从右向左是个位、十位、百位…,分别每一位的权重是100,101,102…。
在十进制中,如图:

假设2进制的1101,如何理解呢?如图:

2.2、10进制转2进制
从图中可以知道:余数作用是求出是当前数的个位。

2.3、2进制转8进制和16进制
原理:二进制数可以按照3个位数(或更一般地,按照任意固定数量的位数)转换到其他进制,这是基于进制转换的基本原理和方便性考虑的。
在8进制中:8进制的数字每一位是0 ~ 7的,0 ~ 7的数字各自写成2进制,最多有3个2进制位就足够了。所以2进制转8进制数的时候,从2进制序列中右边低位开始向左每3个2进制位会换算一个8进制位,剩余不够3个2进制位的直接换算。
注意:0开头的数字,会被当做8进制。

在16进制中:16进制的数字每一位是0 ~ 9、a ~ f的,0 ~ 9、a ~ f的数字各自写成2进制,最多有4个2进制就足够了。比如f的二进制1111,所以在2进制转16进制数的时候,从2进制序列中右边低位开始向左每4个2进制位会换算一个16进制位,剩余不够4个二进制位的直接换算。
注意:16进制表示的时候前面加0x。
例如:2进制的01101011,换成16进制:0x6b。

进制转换总结如下:
- 二进制转八进制,3位二进制
- 二进制转十进制,权和计算法
- 二进制转十六进制,4位二进制
- 十进制转十六进制,先转二进制之后转十六进制
#include <stdio.h>
int main()
{printf("%d\n", 153); // 十进制printf("%d\n", 0153); // 八进制printf("%d\n", 0x153); // 十六进制return 0;
}
输出:
153
107
339
3、原码、反码、补码
二进制:
- 整数的2进制表示方法:原码、反码、补码。
- 有符号整数的2进制三种表示方法均有符号位和数值位两部分。
- 2进制序列中,最高位的1位是被当做符号位,剩余都是数值位。在符号位中,0表示“正”,1表示“负”。
- 原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码。
- 反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
- 补码:反码+1就得到补码。
- 正整数的原、反、补码都相同。
- 负整数的三种表示方法各不相同。
值得一提是:
- 反码得到原码也是可以使用:取反,+1的操作。

对整形来说:数据存放内存中其实存放的是补码,对于整数的计算统一都是用补码来计算。
为什么呢?
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;
同时,加法和减法也可以统一处理(CPU只有加法器),此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
#include <stdio.h>
int main()
{int a = -10;// -10是存放在a中,a是整型变量,是4个字节,32bit位// 10000000 00000000 00000000 00001010 - 原码// 11111111 11111111 11111111 11110101 - 反码// 11111111 11111111 11111111 11110110 - 补码int b = 10;// 00000000 00000000 00000000 00001010 - 原码// 00000000 00000000 00000000 00001010 - 反码// 00000000 00000000 00000000 00001010 - 补码return 0;
}
4、移位操作符
左移操作符:<<
右移操作符:>>
注意:移位操作符的操作数只能是整数。
4.1 左移操作符
移位规则:左边抛弃、右边补0。

#include <stdio.h>
int main()
{int num = 10;// 移位规则:左边抛弃、右边补0int n = num << 1;printf("n = %d\n", n);printf("num = %d\n", num);return 0;
}
输出:
n = 20
num = 10
4.2 右移操作符
移位规则:首先右移运算符分两种:
- 1、逻辑右移:左边用0填充,右边丢弃。
- 2、算术右移:左边用原该值的符号位填充,右边丢弃。(最常见)

注意:右移采取逻辑右移还是算术右移取决于编译器的实现,常见的编译器都是算术右移。
#include <stdio.h>
int main()
{int num = 10;// 移位规则:左边用原该值的符号位填充,右边丢弃。int n = num >> 1;printf("n = %d\n", n);printf("num = %d\n", num);return 0;
}
输出:
n = 5
num = 10
4.3 警告:不要移动负数位
对于移位运算符,不要移动负数位,这个是标准未定义的。
例如:
int num = 10;
num >> -1; //error
5、位操作符
位操作符有:
- &:按位与
- | :按位或
- ^:按位异或
- ~:按位取反
注意:他们的操作数必须是整数。
5.1 例1:观察位操作符
#include <stdio.h>
int main()
{// 10000000 00000000 00000000 00000011 -3的原码// 11111111 11111111 11111111 11111100// 11111111 11111111 11111111 11111101 -3的补码int num1 = -3;// 00000000 00000000 00000000 00000101 5的补码int num2 = 5;// 00000000 00000000 00000000 00000101 按位与,得出5printf("%d\n", num1 & num2);// 11111111 11111111 11111111 11111101 按位或,补码// 10000000 00000000 00000000 00000011 计算,反码+1,得出-3printf("%d\n", num1 | num2);// 11111111 11111111 11111111 11111000 按位异或,补码// 10000000 00000000 00000000 00001000 计算,反码+1,得出-8printf("%d\n", num1 ^ num2);// 00000000 00000000 00000000 00000000 0的补码// 11111111 11111111 11111111 11111111 ~0// 10000000 00000000 00000000 00000001 计算,反码+1,得出-1printf("%d\n", ~0);return 0;
}
输出:
5
-3
-8
-1
5.2 例2:不能创建临时变量(第三个变量),实现两个数的交换。
#include <stdio.h>
int main()
{int a = 100;int b = 202;a = a ^ b;b = a ^ b;a = a ^ b;printf("a = %d b = %d\n", a, b);return 0;
}
输出:
a = 202 b = 100
5.3 例3:求一个整数存储在内存中的二进制中1的个数。
方法1:
// 方法1:
#include <stdio.h>
int main()
{int num = 0;scanf("%d", &num);int count = 0;while (num){if (num % 2 == 1)count++;num = num / 2;}printf("%d\n", count);return 0;
}
在负数中,方法1失效了,比如-1在内存中1的个数有有32,而结果是0。
继续优化,写方法2:
// 方法2:
#include <stdio.h>
int main()
{int num = 0;scanf("%d", &num);int count = 0;for (int i = 0; i < 32; i++){if (num & (1 << i))count++;}printf("%d\n", count);return 0;
}
方法2中是必须循环32次,再继续优化,写方法3:
// 方法3:
#include <stdio.h>
int main()
{int num = 0;scanf("%d", &num);int count = 0;while (num){count++;num = num & (num - 1); }printf("%d\n", count);return 0;
}
在方法3中,每次循环,都会将 num 的最低位的1清零,并将计数器 count 加1。
5.4 例4:如何判断一个数是否是2的次方数?
if (n & (n - 1) == 0)
{n就是2的次方数
}
5.5 例5:二进制位置0或者置1
编写代码将13二进制序列的第5位修改为1,然后再改回0。
13的2进制序列: 00000000 00000000 00000000 00001101
将第5位置为1后: 00000000 00000000 00000000 00011101
将第5位再置为0: 00000000 00000000 00000000 00001101
代码如下:
#include <stdio.h>
int main()
{int a = 13;a = a | (1 << 4);printf("a = %d\n", a);a = a & ~(1 << 4);printf("a = %d\n", a);return 0;
}
6、逗号表达式
逗号表达式:就是用逗号隔开的多个表达式,从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
exp1, exp2, exp3, ... expN
7、下标访问[]、函数调用()
下标引用操作符:操作数为一个数组名 + 一个索引值。
int arr[10]; // 创建数组
arr[9] = 10; // 使用下标引用操作符
[ ] 的两个操作数是arr和9。
函数调用操作符:接受一个或者多个操作数,第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
8、结构成员访问操作符
点操作符(.):直接访问结构体成员,点操作符接受两个操作数。
使用方式:结构体变量.成员名。如下:
#include <stdio.h>
struct Point
{int x;int y;
}p = { 1,2 };int main()
{printf("x:%d, y:%d\n", p.x, p.y);return 0;
}
运行:
x:1, y:2
箭头操作符(->):间接访问结构体成员。 有时候我们得到的不是⼀个结构体变量,而是得到了一个指向结构体的指针。
使用方式:结构体指针->成员名。如下:
#include <stdio.h>
struct Point
{int x;int y;
}p = { 1,2 };int main()
{struct Point* ptr = &p;ptr->x = 10;ptr->y = 20;printf("x:%d, y:%d\n", ptr->x, ptr->y);return 0;
}
运行:
x:10, y:20
9、操作符的属性:优先级、结合性
C语⾔的操作符有2个重要的属性:优先级、结合性,这两个属性决定了表达式求值的计算顺序。
结合性:如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符是左结合,还是右结合,决定执行顺序。大部分运算符是左结合(从左到右执行),少数运算符是右结合(从右到左执行),比如赋值运算符( = )。
建议大概记住这些操作符的优先级就行,其他操作符在使用的时候查看下面表格就可以了。
• 圆括号(())
• 自增运算符(++),自减运算符(--)
• 单⽬运算符(+和-)
• 乘法(*),除法(/)
• 加法(+),减法(-)
• 关系运算符(<、>等)
• 赋值运算符(=)

官方文档:https://zh.cppreference.com/w/c/language/operator_precedence
10、其他
10.1 整型提升
C语言中整型算术运算总是至少以缺省整型类型的精度来进行的。
缺省:在计算机科学和相关领域中,它通常指的是“默认”或“预设”的意思。
整型提升:为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型。
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
通用CPU(general-purposeCPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
char a, b, c;
...
a = b + c;
b和c的值被提升为普通整型,然后再执行加法运算。加法运算完成之后,结果将被截断,然后再存储于a中。
如何进行整体提升呢?
- 有符号整数提升是按照变量的数据类型的符号位来提升的。
- 无符号整数提升,高位补0。
// 负数的整形提升
char c1 = -1;
整型提升:
11111111 11111111 11111111 11111111
// 正数的整形提升
char c2 = 1;
整型提升:
00000000 00000000 00000000 00000001
10.2 算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。
long double
double
float
unsigned long int
long int
unsigned int
int
如果某个操作数的类型在上面这个列表中排名靠后,那么首先要转换为另外一个操作数的类型后执行运算。
完。
相关文章:
[C]基础8.详解操作符
博客主页:算法歌者本篇专栏:[C]您的支持,是我的创作动力。 文章目录 0、总结1、操作符的分类2、二进制和进制转换2.1、2进制转10进制2.2、10进制转2进制2.3、2进制转8进制和16进制 3、原码、反码、补码4、移位操作符4.1 左移操作符4.2 右移操…...
MySQL篇之对MySQL进行参数优化,提高MySQL性能
1. MySQL参数优化说明 MySQL 参数调优是提高数据库性能的重要手段之一。通过调整 MySQL 的配置参数,可以优化查询速度、提升并发处理能力、减少资源消耗等。 MySQL 的性能优化涉及到多个方面,包括内存管理、磁盘 I/O、查询优化、连接管理、复制配置等。…...
Vue 3 的 keep-alive 及生命周期钩子
在 Vue 3 中,keep-alive 是一个内置组件,用于提高性能和减少不必要的组件销毁与重建。它与组件的生命周期紧密相关,特别是在动态组件和路由切换场景下,能够缓存组件的状态并避免重新渲染。 而 onActivated 和 onDeactivated 是 …...
ComfyUI实现老照片修复——AI修复老照片(ComfyUI-ReActor / ReSwapper)解决天坑问题及加速pip下载
AI修复老照片,试试吧,不一定好~~哈哈 2023年4月曾用过ComfyUI,当时就感慨这个工具和虚幻的蓝图很像,以后肯定是专业人玩的。 2024年我写代码去了,AI做图没太关注,没想到,现在ComfyUI真的变成了工…...
OpenEuler学习笔记(十一):OpenEuler上搭建LAMP环境
LAMP环境指的是Linux、Apache、MySQL(或MariaDB)和PHP的组合,下面为你介绍在OpenEuler上搭建LAMP环境的详细步骤: 1. 系统更新 首先要更新系统中的软件包,保证系统处于最新状态。 sudo dnf update -y2. 安装Apache…...
Mongodb 慢查询日志分析 - 1
Mongodb 慢查询日志分析 使用 mloginfo 处理过的日志会在控制台输出, 显示还是比较友好的. 但是如果内容较大, 就不方便查看了, 如果可以导入到 excel 就比较方便筛选/排序. 但是 mloginfo 并没有提供生成到 excel 的功能. 可以通过一个 python 脚本辅助生成: import pandas…...
MySQL面试题2025 每日20道【其四】
1、你们生产环境的 MySQL 中使用了什么事务隔离级别?为什么? 中等 在生产环境中,MySQL数据库的事务隔离级别通常由开发团队或数据库管理员根据应用的需求来设定。MySQL支持四种标准的事务隔离级别: 读未提交(Read Unc…...
微服务学习-Nacos 注册中心实战
1. 注册中心的设计思路 1.1. 微服务为什么会用到注册中心? 服务与服务之间调用需要有服务发现功能;例如订单服务调用库存服务,库存服务如果有多个,订单服务到底调用那个库存服务呢(负载均衡器)࿰…...
k8s服务StatefulSet部署模板
java 服务StatefulSet部署模板 vim templates-test.yamlapiVersion: apps/v1 kind: StatefulSet metadata:labels:app: ${app_labels}name: ${app_name}namespace: ${app_namespace} spec:replicas: ${app_replicas_count}selector:matchLabels:app: ${app_labels}template:la…...
07 区块链安全技术
概述 区块链的安全特性 区块链解决了在不可靠网络上可靠地传输信息的难题,由于不依赖与中心节点的认证和管理,因此防止了中心节点被攻击造成的数据泄露和认证失败的风险。 区块链安全防护的三大特点 共识机制代替中心认证机制数据篡改“一发动全身”…...
Adobe的AI生成3D数字人框架:从自拍到生动的3D化身
一、引言 随着人工智能技术的发展,我们见证了越来越多创新工具的出现,这些工具使得图像处理和视频编辑变得更加智能与高效。Adobe作为全球领先的创意软件公司,最近推出了一项令人瞩目的新技术——一个能够将普通的二维自拍照转换成栩栩如生的三维(3D)数字人的框架。这项技…...
dfs专题四:综合练习
key:画出决策树(就是找个简单例子模拟一下的树状决策图) dfs传参 or 全局变量: int, double等常量/比较小的变量,可以dfs参数传递vector等线性O(N)变量,要用全局变量 回溯&#x…...
【线性代数】列主元法求矩阵的逆
列主元方法是一种用于求解矩阵逆的数值方法,特别适用于在计算机上实现。其基本思想是通过高斯消元法将矩阵转换为上三角矩阵,然后通过回代求解矩阵的逆。以下是列主元方法求解矩阵 A A A 的逆的步骤: [精确算法] 列主元高斯消元法 步骤 1&am…...
大写——蓝桥杯
1.题目描述 给定一个只包含大写字母和小写字母的字符串,请将其中所有的小写字母转换成大写字母后将字符串输出。 输入描述 输入一行包含一个字符串。 输出描述 输出转换成大写后的字符串。 输入输出样例 示例 输入 LanQiao输出 LANQIAO评测用例规模与约定 对…...
HTML `<head>` 元素详解
在 HTML 文档中,<head> 元素是一个非常重要的部分,它包含了文档的元数据(metadata)和其他与文档相关的信息。虽然 <head> 中的内容不会直接显示在网页上,但它对网页的行为、样式和搜索引擎优化(…...
一文速通stack和queue的理解与使用
CSTL之stack和queue 1.stack1.1.stack的基本概念1.2.stack的接口 2.queue2.1.queue的基本概念2.2.queue的接口 3.priority_queue3.1.priority_queue的基本概念3.2.priority_queue的接口3.3.仿函数 4.容器适配器5.deque5.1.deque的简单了解5.2.deque的优缺点 🌟&…...
Antd React Form使用Radio嵌套多个Select和Input的处理
使用Antd React Form使用Radio会遇到嵌套多个Select和Input的处理,需要多层嵌套和处理默认事件和冒泡,具体实现过程直接上代码。 实现效果布局如下图 代码 <Formname"basic"form{form}labelWrap{...formItemLayoutSpan(5, 19)}onFinish{on…...
Vue - toRefs() 和 toRef() 的使用
一、toRefs() 在 Vue 3 中,toRefs()可以将响应式对象的属性转换为可响应的 refs。主要用于在解构响应式对象时,保持属性的响应性。 1. 导入 toRefs 函数 import { toRefs } from vue;2. 将响应式对象的属性转换为 ref const state reactive({count: 0,message:…...
Python3 OS模块中的文件/目录方法说明九
一. 简介 前面文章简单学习了 Python3 中 OS模块中的文件/目录的部分函数。 本文继续来学习 OS 模块中文件、目录的操作方法:os.pipe() 方法、os.popen() 方法。 二. Python3 OS模块中的文件/目录方法 1. os.pipe() 方法 os.pipe() 方法用于创建一个管道, 返回…...
OpenCV文字绘制支持中文显示
OpenCV版本:4.4 IDE:VS2019 功能描述 OpenCV绘制文本的函数putText()不支持中文的显示,网上很多方法推荐的都是使用FreeType来支持,FreeType是什么呢?FreeType的官网上有介绍 FreeType官网 https://www.freetype.or…...
【FMCW雷达】频率调制连续波FMCW雷达系统(从波形生成到利用小胞平均常误报率CA-CFAR进行目标检测)【含Matlab源码 15242期】含报告
💥💥💥💥💥💥💥💥💞💞💞💞💞💞💞💞💞Matlab武动乾坤博客之家💞…...
三星 Infinite AI 葡萄酒冰箱:智能厨房新尝试能否突围?
AI 加持,葡萄酒管理新体验周一,三星推出了 Infinite AI 葡萄酒冰箱,目前仅在韩国有售。这款冰箱采用了“AI 葡萄酒管理器”,借助安装在顶部的“AI 视觉”摄像头,能检测用户放入或取出的酒瓶及位置,还能分析…...
Monaco-Editor插件使用小坑
无法通过鼠标进行选中文本<div id"monacoEditor" class"monacoEditor"></div>外层添加了splinter拖拽组件,导致mousemove事件被拦截,给monaco-editor添加css:pointer-events:auto.monacoEditor .…...
提升效率:用快马AI一键生成windows18-hd19风格的CSS组件库
提升效率:用快马AI一键生成windows18-hd19风格的CSS组件库 最近在做一个需要windows18-hd19设计风格的项目,这种风格的界面元素特别多,手动编写样式简直让人头大。光是调色板、阴影效果这些基础样式就要折腾半天,更别说那些复杂的…...
Jimeng LoRA环境部署教程:Python+Torch+CUDA兼容性避坑与版本匹配指南
Jimeng LoRA环境部署教程:PythonTorchCUDA兼容性避坑与版本匹配指南 1. 项目简介 Jimeng LoRA(即梦LoRA)是一个专门为LoRA模型测试设计的轻量级文本生成图像系统。这个项目的核心价值在于它能让你只用加载一次基础模型,然后快速…...
如何三步搞定iOS微信聊天记录完整导出:隐私保护与数据备份终极指南
如何三步搞定iOS微信聊天记录完整导出:隐私保护与数据备份终极指南 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 还在为无法永久保存重要微信对话而烦恼吗&…...
GooglePlay多账号管理神器推荐:5款工具帮你轻松实现合规隔离(2025亲测有效)
GooglePlay多账号管理实战指南:2025年高效合规工具与策略 在移动应用生态中,Google Play作为全球最大的应用分发平台,其严格的账号管理政策让许多开发者感到头疼。特别是对于那些需要运营多个账号的开发者来说,如何在合规前提下实…...
玩转ESP32-S3调试:GDB高级命令与自定义调试技巧大全
玩转ESP32-S3调试:GDB高级命令与自定义调试技巧大全 调试嵌入式系统时,GDB的强大功能往往被低估。对于ESP32-S3开发者来说,掌握GDB的高级调试技巧可以显著提升解决复杂问题的效率。本文将深入探讨如何利用GDB的watch命令、自定义命令、跳转执…...
WPF进阶:Canvas动态图形绘制与交互实现
1. Canvas动态图形绘制基础 WPF中的Canvas就像一块无限延伸的画布,我们可以在这块画布上自由地绘制各种图形元素。与静态绘制不同,动态绘制的魅力在于图形能够根据用户操作实时变化。我刚开始接触Canvas时,最让我兴奋的就是看到鼠标移动时能实…...
FASTDDS-Python 实战:从零构建分布式通信环境
1. 为什么选择Fast DDS-Python? 在物联网和机器人系统中,设备间的实时通信是个硬需求。想象一下,你正在开发一个智能仓储机器人系统,需要让多台机器人在复杂环境中协同工作。这时候,传统的HTTP请求-响应模式就显得力不…...
