当前位置: 首页 > news >正文

C语言操作符

前言

本人的技术笔记会优先发布在个人站点longyxblg.cn

操作符分类

原码、反码、补码

整数的2进制表示方法有三种,即原码、反码、补码。

有符号的三种表示方法均有符号位和数值位两部分组成。

首位被当作符号位,剩下的均为数值位。

符号位用 0 表示正,用 1 表示负。

正整数的原码、反码、补码都相同。

负整数的三种表示方法各不相同。

  • 原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码。

  • 反码:原码的数值位取反,符号位不变。( 0 变 1 ,1 变 0)

  • 补码:反码 + 1。

例如:
对于整型来说,其实存放在内存中的就是他的补码。

inta=-10;// 原码就是 a 的二进制表示// 一个整型数在内存中占 4 个字节(32 位),一个字节由8个 bit 位组成,所以 a 的二进制表示为:// 10000000 00000000 00000000 00001010 就是原码// 11111111 11111111 11111111 11110101 就是 a 的反码// 11111111 11111111 11111111 11110110 就是 a 的补码

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路

移位操作符

全程操作的都是数据的补码。

左移位操作符

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

inta=10;// 00000000 00000000 00000000 00001010intnum=a<<1;// 左移一位,相当于乘以 2// 00000000 00000000 00000000 00010100printf("%d\n",num);

inta=-10;// 10000000 00000000 00000000 00001010 就是 a 的原码// 11111111 11111111 11111111 11110101 就是 a 的反码// 11111111 11111111 11111111 11110110 就是 a 的补码intnum=a<<1;// 11111111 11111111 11111111 11101100 就是 a 左移一位后的结果,这是补码// 11111111 11111111 11111111 11101011 就是 a 左移一位后的反码// 10000000 00000000 00000000 00010100 就是 a 左移一位后的原码

右移位操作符

右移位操作符分两种情况:逻辑右移和算术右移

逻辑移位规则:右边抛弃,左边补0

inta=10;// 00000000 00000000 00000000 00001010intnum=a>>1;// 右移一位,相当于除以 2// 00000000 00000000 00000000 00000101printf("%d\n",num);

算术移位规则:右边抛弃,左边用概该数的符号位填充

inta=-10;// 10000000 00000000 00000000 00001010 就是 a 的原码// 11111111 11111111 11111111 11110101 就是 a 的反码// 11111111 11111111 11111111 11110110 就是 a 的补码intnum=a>>1;// 11111111 11111111 11111111 11111011 就是 a 右移一位后的结果// 11111111 11111111 11111111 11111010 就是 a 右移一位后的反码// 10000000 00000000 00000000 00000101 就是 a 右移一位后的补码printf("%d\n",num);


对于移位操作符,不能移动负数位,这个标准是未定义的。

位操作符

&// 按位与|// 按位或^// 按位异或!// 按位取反

注:他们操作的必须是整数。

& 是双目操作符,对两个数的补码进行操作,都为1是1,有0就是0

| 是双目操作符,对两个数的补码进行操作,有1就是1,都是0位0

^ 是双目操作符,对两个数的补码进行操作,位相同为0,不同为1

int num1 = 10; // 00000000 00000000 00000000 00001010 就是 num1 的二进制表示 int num2 = 20; // 00000000 00000000 00000000 00010100 就是 num2 的二进制表示 printf("%d\n", num1 & num2); // 都是1才是1,否则为0 // 00000000 00000000 00000000 00001010 // 00000000 00000000 00000000 00010100 // 00000000 00000000 00000000 00000000 printf("%d\n", num1 | num2); // 有1为1,否则为0 // 00000000 00000000 00000000 00001010 // 00000000 00000000 00000000 00010100 // 00000000 00000000 00000000 00010110 printf("%d\n", num1 ^ num2); // 相同为0,不同为1 // 00000000 00000000 00000000 00001010 // 00000000 00000000 00000000 00010100 // 00000000 00000000 00000000 00010110 printf("%d\n", ~ num1); // 按位取反 // 1取0,0取1 // 00000000 00000000 00000000 00001010 // 11111111 11111111 11111111 11110101 就是 num1 的按位取反结果,这是补码 // 11111111 11111111 11111111 11110100 这是反码 // 10000000 00000000 00000000 00001011 这是原码

使用位操作符实现交换两变量的值

假设现在有一变量 x ,那么 x 一定满足 x ^ x = 0, 0 ^ x = x , 对于变量 a,b ,满足 (a ^ b) ^ c = a ^ (b ^ c),即可推导出

inta=0;intb=0;scanf("%d %d",&a,&b);a=a^b;b=a^b;a=a^b;printf("a = %d b = %d",a,b);

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

对于 1 来说,他与任意一个整数进行 & 运算只会出现 0 和 1 两种结果。

00000000000000000000000000000001// 1在内存中的存储

那么就可以这么设计

// 计算一个整数的二进制表示中有多少个 1intnum=0;intcount=0;scanf("%d",&num);for(inti=0;i<32;i++){// 1与任意一个整数进行按位与运算,如果该整数的二进制表示中对应位是 1,那么结果就是 1,否则就是 0if(1&num>>i){count++;// 说明 num 的二进制表示中第 i 位是 1,那么就把 count 加 1}}printf("有 %d 个 1\n",count);

还有一种效率更高的算法,不需要循环32次

intnum=-1;intcount=0;while(num){count++;num=num&(num-1);// 这个操作会把 num 的二进制表示中最后一个 1 变成 0}printf("有 %d 个 1\n",count);

这个算法利用的就是每次 num & num - 1 会将这个数放在末尾的1消掉。

直到这个数变成0为止,统计这个过程执行了多少次,就知道 num 的二进制表示中有多少个 1 了。


注:只有在补码存储下该公式成立

逗号表达式

指用逗号隔开的多个表达式。从左向右依次执行,整个表达式的结果是最后一个表达式的结果。

inta=3;intb=4;intc=(a+b,a*b,a-b);printf("%d\n",c);

这儿有一串代码

a=test1();test2();while(a>0){// 业务处理test2();}

那么根据逗号表达式的计算,还可以这么写

while(a=test1(),test2(),a>0){// 业务处理test2();}

标访问[]和函数调用()

这俩没啥好说的

intarr[10];//创建数组 arr[9]=10;//使用下标引用操作符。[]的两个操作数是arr和9
voidtest1(){printf("hehe\n");}voidtest2(constchar*str){printf("%s\n",str);}intmain(){test1();//这里的()就是作为函数调用操作符。test2("hello world.");//这里的()就是函数调用操作符。return0;}

结构体访问操作符

这一块儿放到结构体。

表达式求值

整型提升

C语言中整型算术运算总是至少以缺省整型类型的精度来进行的。

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

chara=3;charb=127;charc=a+b;printf("%d ",c);

这里 a 和 b 在进行相加之前,就会先提升为普通整型,再执行加法计算。计算完成后,结果在被截断后存放进 c 中。

整型提升的规则是

  • 有符号整数提升是按照变量的数据类型的符号位来提升的

  • 无符号整数提升,高位补0

charc=a+b;// a: 00000000 00000000 00000000 00000011// b: 00000000 00000000 00000000 01111111// a + b: 00000000 00000000 00000000 10000010// 存到 c 中时,c 只有1个字节,所以只保留最后8位// c: 10000010 这是补码// 而 %d 输出的是有符号整数// 所以C又会发生整型提升,c会被提升成int类型// 适用有符号整数提升是按照变量的数据类型的符号位来提升的// c: 11111111 11111111 11111111 10000010 这是补码// 11111111 11111111 11111111 10000001 这是反码// 10000000 00000000 00000000 01111110 这是原码

所以最后输出的是 -126

算术转换

如果某个操作符的各个操作数属于不同的类型,那么需将其中一个操作数的类型转换为另一个操作数的类型。

如果某个操作数的类型在上面这个列表中排名靠后,那么首先要转换为另外一个操作数的类型后执行运算。

http://www.jsqmd.com/news/1337880/

相关文章:

  • 基于OpenClaw与LLM的低成本企业级AI智能体实战:重塑客服与销售自动化
  • 预埋钢套管怎么选才靠谱?2026年行业数据与厂家实力深度解析! - 优质品牌商家
  • C语言面试核心考点解析:指针、内存管理与底层原理实战指南
  • 严肃科研容不下“概率游戏”:为什么通用大模型难以直接适配生物医学的严谨调研
  • 颠覆传统谐振腔范式——Nature子刊报道随机克尔光频梳首次实验实现
  • 自己动手开发编译器(六)上下文无关语言和文法
  • 2026 实测:一键去除视频水印怎么操作?AI视频去水印软件方法盘点 - 免费软件工具方法教程
  • 2026年血红素铁补铁剂市场深度观察:从含铁量竞赛到吸收效率建模
  • Cloudflare Workers AI实战:边缘部署Kimi与GLM大模型指南
  • 从扛着库存跑到轻装上阵,你的私域直播系统选对了吗?
  • C++链表翻转:头插法原理与实现详解
  • UnityExplorer实战指南:实时调试与游戏逆向分析工具详解
  • 2026 年新发布:晋中值得关注的导热油炉定制厂家哪个好,工厂里烧了十年的它,居然比电锅炉省出半套设备钱?-智能锅炉 - 行业鉴选官
  • Overleaf自定义中文字体全攻略:从原理到实践
  • 交通控制基础理论:从交通流模型到信号配时优化实践
  • 欧盟DSSC认证对软件测试的影响与应对策略
  • 中介孟德尔随机化:从因果推断到机制解析的完整指南
  • 短剧出海翻译服务商怎么选?重点看跨集一致性
  • 量化回测实战指南:从双均线策略到避免未来函数陷阱
  • 材料力学三大模量:杨氏、剪切、体积模量解析与工程应用
  • 从模糊需求到清晰项目:技术落地的核心能力拆解
  • 自己动手开发编译器(三)有穷自动机
  • 【办公类106-02】20260805问卷星新生家长调查问卷(deep seek制作python词云图
  • 德鲁克影响管理世界几十年,这本经典书籍帮你看懂他的思想
  • JSM4826 是一款60V 双通道独立 N 沟道增强型功率 MOSFET
  • 本地大模型参数调优实战:从Temperature到Top-p的深度解析与实验指南
  • AI绘画提示词工程实战:从复杂指令到精准图像生成
  • 解决codex接入Deepseek后不能识别图片!!!!别再让 Codex 当“文盲“了!这个开源 Skill 让它直接看懂你的截图
  • 开源参与指南:从心理建设到代码贡献的完整路径
  • Godot 4.x 实现 JRPG 回合制战斗系统:架构、状态机与实战优化