news 2026/5/17 1:32:21

初始C语言——运算符

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
初始C语言——运算符

接下来我们将继续探讨C语言的基础知识。上一章讲解了数据类型的概念,本章将重点介绍运算符的相关内容。让我们直接进入主题,开启C语言运算符的学习之旅。

  • 各类数值型数据间的混合运算
  • 隐式转换
  • 显示转换
  • C运算符和C表达式
  • 算术运算符
  • 赋值运算符
  • 关系运算符
  • 逻辑运算符
  • 逗号运算符
  • 位运算

各类数值型数据间的混合运算

首先大家先可以知道整型、浮点型、字符型数据可以进行混合运算,如:

10-‘a'*1.5=10-97*1.5//保证参与运算的都是数字=10.0-97.0*1.5//临时申请一块空间,保证运算数据类型一致、运算完毕,临时空间回收(隐式转换)

解释:整型、浮点型、字符型能进行混合运算,核心原因是它们都属于数值型数据——字符本质是特殊的数值型(参与数值计算时使用ASCll码,取值范围是0~127)

运算规则:若参与运算的两个数类型不同,会先将类型转换为一致后再运算。转换规则分为隐式转换显示转换

隐式转换

隐式转换又被称为自动类型转换,由编译系统自动控制规则是将低等级提示为高等级类型。

转换关系(由低到高)如图所示:

注:

①int → unsigned int → long → double(int与unsigned的转换顺序可能因平台(如操作系统位数)和编译器不同存在差异,需结合具体环境判断。)
②char /short →int(必然转换)
​③float → double (必然转换,C语言默认以双精度浮点型(double)进行浮点运算,因此float类型参与运算时会自动隐式转换为double)

关键注意事项

混合运算中的类型转换仅在运算过程中临时生效,不会改变原变量的类型和内存的存储形式(所谓类型提升,其实就是系统运算时,将原本的数据产生一份副本,由副本数据参与计算,计算完毕,副本销毁,原数据不受影响

举例:

inta=10;//a的类型始终是intdoublec=a+22.5;//运算时a临时转换为double,等价于10.0 + 22.5,其实就是a的double类型的副本参与运算a=21;//a仍然是int,变量一旦申请其内存大小不会发生改变

显示转换

显示转换又被称作强制类型转换,由程序员手动指定转换类型。
语法说明:

double)a://将变量 a 的值强制转换为double类型。​(int)(x+y)://将表达式 x+y 的结果转换为int类型。(括号比较包含整个表达式,否则转换x)int)x+y://仅将变量x转换为int类型,在于y进行计算(括号仅作用于x)

举例:

doublea=2,b=3;doublec=(int)a+b;//第1步:显示将a转换为int(2),第2步:混合运算int转化为double,最终等价于2.0 + 3.0doublenum1=12.55;intnum2=(int)num1;//显示将num1转换为int类型,浮点型转整型,舍弃小数部分,不是四舍五入)printf("%d\n",num2);num1=15;

关键注意事项

1、强制类型转换仅在运算过程中临时改变值的类型,不会修改原变量的类型和内存存储形式;
2、浮点型转整型时直接舍弃小数部分,不进行四舍五入;
3、转换后的类型需与接收变量的类型匹配,避免数据溢出或精度丢失。

C运算符和C表达式

C运算符

C表达式

运算数(常量、变量、表达式)和运算符按照C语法规则连接而成的式子(表达式 = 运算数 +运算符)

名称举例结果说明与说明
算术表达式2 + 6.7 *3.5数值类型(int或double等取决于运算数类型)
关系表达式x > 0 、y < z+6布尔类型(C语言用0表示假,非0表示真)
逻辑表达式x > 0 && y > 0布尔类型
赋值表达式a = 5.6、sum += i、a = b = c = 5;左侧变量的类型,运算顺序自右向左
逗号表达式x = 3, y += 4 , z -= 8最后一个表达式的类型,结果为最后一个表达式的值

注:注意逗号表达式和逗号分隔符。

逗号运算符:在表达式中,用来连接多个表达式,有 “顺序执行 + 返回最后一个值” 的作用(比如 (a=1, b=2))。
逗号分隔符:用来分隔函数参数、变量声明等,没有 “逗号表达式” 的特性(比如 printf(“%d”, a) 里的逗号,或者 int a, b, c; 里的逗号)
逗号表达式: x = 3, y += 4 , z -= 8 最后一个表达式的类型,结果为最后一个表达式的值

C语言运算符优先级与结合性

C语言通过优先级和结合性规定表达式的求值顺序:优先级高的运算符先执行;优先级相同时,按结合性顺序执行。

简化优先级表(从高到低):

优先级运算符类别运算符示例结合性
1括号、下标、成员访问()[].->从左向右
2后缀自增 / 自减a++a--从左向右
3前缀自增 / 自减、逻辑非等++a--a!sizeof&-(负号)从右向左
4强制类型转换(type)从右向左
5算术乘除、取余*/%从左向右
6算术加减+-从左向右
7位左移 / 右移<<>>从左向右
8关系运算符(比较大小)><>=<=从左向右
9关系运算符(相等判断)==!=从左向右
10位与&从左向右
11位异或^从左向右
12位或|从左向右
13逻辑与&&从左向右
14逻辑或||从左向右
15条件运算符?:从右向左
16赋值运算符(含复合赋值)=+=-=*=/=从右向左
17逗号运算符,从左向右

算术运算符

运算符功能类型注意事项
+加法/正值双目/单目单目时表示正值,如+5
-减法/负值双目/单目单目时表示负值,如-5
*乘法双目
/除法双目除数不能为0,整型相除结果为整型,如1/2=0
%取余双目仅适用于整型;结果符合与被除数一致;
++自增单目是变量值增1
自减单目使变量值减1

面试题:

1/2+1/2的结果是多少?答案是0(两个整数相除结果为00+0=01.0/2+1.0/2.0的结果是多少?答案是1.0(两个浮点型运算,0.5+0.5=1.0

自增、自减运算符(++/–)

作用:使变量值增1或者减1,适用于算术类型(整型、字符型、浮点型等)的可修改左值,实践中常用整型和字符型变量。

核心区别:运算符位置绝对变量值的更新时机。

++i/–i(前缀自增/自减)

运算规则:先更新变量值,后使用变量(先计算,后使用,自己计算,别人使用)

​ 步骤一:变量值自增1(i = i+1)或自减1(i = i-1)

​ 步骤二:使用更新后的变量值参与计算、赋值、比较等操作。

i++/i–(后缀自增/自减)

运算规则:先使用变量,后更新变量值(先使用,后计算,)

​ 步骤一:使用变量当前值参与赋值、计算、比较等操作。

​ 步骤二:变量值自增1(i = i+1)或自减1(i = i-1)

赋值运算符

基本赋值运算符

作用:将右侧运算数(常量、变量、表达式)的值存入左侧变量的内存单元。

核心规则:

1、运算顺序:自右向左(先计算右侧表达式,再赋值给左侧变量)

2、左侧必须是可修改的变量(左值),不能是常量或表达式,如5 = a、a + b = 3均为非法

3、赋值表达式的值等于左侧变量的最终值,如 b = a = 5 中,a = 5 的值为5,再赋值给b,最终b = 5.

类型转换规则(赋值时)

若赋值运算符 = 两侧类型不一致,会自动进行类型转换,转换规则如下:

源类型目标类型转换规则举例
浮点型{double、float}整型(short、int、long)舍弃小数部分、仅保留整数部分int a = 5.9 → a = 5
整型(short、int、long)浮点型(double、float)数值不变,以目标浮点型格式存储double b = 5 → b = 5.000000
字符型(char)整型(short、int、long)字符的ASCll码存入整型低8位,高位补0int c = ‘A’ → c = 65
长整型(long long)短整型截取低字节数据,可能导致数据溢出short d = 32768(int)→溢出

复合赋值运算符

复合赋值运算符基本赋值运算符算术运算符/位运算的结合,简化代码书写

常见复合赋值运算符:

运算符等价形式举例结果
+=a = a + bint a=1; a+=3;a=4(1+3)
-=a = a - bint a=5; a-=2;a=3(5-2)
*=a = a * bint a=3; a*=4;a=12(3*4)
/=a = a / bint a=8; a/=2;a=4(8/2)
%=a = a % bint a=7; a%=3;a=1(7%3)
&=a = a & bint a=5; a&=6;a=4(5&6)
|=a = a| bint a=5;a|=6;a=7(5|6)
^=a = a ^ bint a=5; a^=6;a=3(5^6)
<<=a = a << bint a=2; a<<=1;a=4(2<<1)
>>=a = a >> bint a=4; a>>=1;a=2(4>>1)

关系运算符

作用:比较两个运算数的大小或相等关系,结果为布尔类型(C语言用0表示假,非0表示真)

常用关系运算符(均为双目运算符):

运算符功能举例结果(假设a=5,b=4)
>大于a >b1(true-真)
<小于a <b0(false-假)
>=大于等于a>=51(true-真)
<=小于等于b<=30(false-假))
==等于a == 51(true-真)
!=不等于a !=b1(true-真)

关键注意事项:
1、避免链式比较:C语言不推荐 0 <= score <= 100(逻辑比较)这类链式写法,逻辑上会报错,编译不报错。

​ 错误原因:编译器按左结合性依次计算,如 0 <= score <=100,等价于(0 <=score) <=
100,结果永远为真,无论score是否在0~100范围内。
​ 正确写法:使用逻辑与运算符 score >= 0 && score <=100

2、浮点型相等比较需要用差值法介绍:由于浮点型存储精度限制(如1.1无法精确存储),直接用 == 判断相等会导致逻辑错误。

错误示例:

floata=1.1f+1.2f;// 2.300000floatb=2.3f;printf("a=%.20f,b=%.20f,%d\n",a,b,a==b);//a=2.30000019073486328125,b=2.29999995231628417969,0

正确写法:
判断两数差值的绝对值是否小于极小值(如1e-6,即0.000001),需引入math.h头文件使用fabs函数(取绝对值)

#include<math.h>#defineEPSle-6//定义误差允许范围if(fabs(a-b)<EPS){//并不是真实的相等,只是判断两个数差值的绝对值是否在可接受的范围内}

浮点型比较总结:

逻辑运算符

作用:布尔类型的运算数进行逻辑运算,结果仍然为布尔类型(0表示假,非0表示真)

运算符名称类型运算规则短路效果
逻辑非单目真→假,假→真无(仅一个运算数)
&&逻辑与双目全1则1,有0则0左侧为假时,右侧不执行
||逻辑或双目全0为0,有1唯1左侧为真时,右侧不执行

逻辑非 !

仅作用于右侧运算数,优先级较高
​仅同一运算数取非奇数次,结果与原值相反;取非偶数次,结果与原值相同。

举例:

inta=5,b=0;printf("%d\n",!a);// 0(a非0为真,!真=假)printf("%d\n",!b);// 1(b=0为假,!假=真)printf("%d\n",!(a%2!=0));// 0(a%2!=0为真,!真=假)printf("%d\n",!!a);// 1(!!真=真,自右向左)

逻辑与&&

运算顺序:自左向右
​短路效果:若左侧运算数(表达式)为假,右侧运算数不再执行(因最终结果必为假,无需计算右侧)。

举例:

intscore=90;printf("%d\n",score>=0&&socre<=100);intx=3,y=5;if(x>y&&y++)//此时触发短路{//不执行}printf("y=%d\n",y);//输出 y = 5

逻辑或||

​ 运算顺序:自左向右
​ 短路效果:若左侧运算数(表达式)为真,右侧运算数不再执行(因最终结果必为真,无需计算右侧)。

举例:

intyear=2025;//闰年判断:能被4整除且不能被100整除或者能被400整除printf("%d\n",(year%4==0&&year%100!=100)||year%400==0)

逗号运算符

作用:将多个表达式串联成一个表达式(又称作顺序求值运算符),按从左到右的顺序执行每一个表达式。

核心规则:

​ 1、求值顺序:从左往右依次计算每个表达式的值
​ 2、最终结果:整个逗号表达式的值等于最后一个表达式的值。
​ 3、优先级:逗号运算符的优先级是所有运算符中,优先级最低的。需要注意括号的使用。

举例:

#include<stdio.h>intmain(){//变量,函数中的逗号,叫做逗号分隔符inta=0,b=0;//整体是赋值表达式,(a = 3,b = 5, a + b)内是逗号表达式,结果是最后一个表达式的结果,8intresult=(a=3,b=5,a+b);//根据条件判断的逗号表达式intx=10,y=20;intmax=(x++,y++,(x>y)?x:y);//这个整体是赋值表达式,只有后面(x++,y++,(x>y) ? x : y)才是逗号表达式}

建议:如果无法区分逗号表达式和赋值表达式,就看谁最后执行,谁最后执行,就是谁!

位运算

(记住在计算机中参与运算的都是补码,正数原码=反码=补码)

作用:直接对数据的二进制位(bit)进行运算,常用于嵌入式开发、底层编程、数据加密等场景。

前提:参与位运算的操作数需要先转换为二进制(signed类型按补码存储、unsigned类型按原码存储)。

按位取反(~)

​ 类型:单目运算符(只有一个运算数)

​ 规则:对数据的每一个二进制位取反(0→1,1→0)

​ 注意:整数在内存中以补码形式存储,取反需要结合补码规则转换为十进制(如:~5 = -6)

演示:以8位二进制为例

十进制二进制原码按位取反十进制结果
50000 01011111 1010-6

举例:

printf("%d\n",~5);//输出:-6(32位系统中补码运算结果)

按位与(&)

​ 类型:双目运算符

​ 规则:对应二进制位均为1时,结果为1;否则为0(有0则0)

演示案例:以8位二进制为例

十进制二进制补码运算十进制二进制补码结果(二进制)结果(十进制)
50000 0101&60000 01100000 01004

举例:

printf("%d\n",5&6);

常用场景:

1、按位清零:将特定位设为0(如num & 0xFFFFFFF将num的最低设置为0,后续展开讲解)

2、提取特定位:获取数据的某几段(如num & 0x0F提取num的低4位)寄存器、flash(相对大一点的数据)、sdcard(持久化的文件)

按位或(|)

​ 类型:双目运算符

​ 规则:对应二进制位有一个为1时,结果为1;否则为0(有1则1)

演示案例:以8位二进制为例

十进制二进制补码运算十进制二进制补码结果(二进制)结果(十进制)
50000 0101&60000 01100000 01117

举例:

printf("%d\n",5|6);//7

按位异或(^)

​ 类型:双目运算符

​ 规则:对应二进制位相同为0,不同为1(相同为0,不同为1)

演示案例:以8位二进制为例

十进制二进制补码运算十进制二进制补码结果(二进制)结果(十进制)
50000 0101^60000 01100000 00113

常用场景:

​ 1、数据交换:无需临时变量交换整数(a = a ^ b; b = a ^ b;a = a ^ b)

​ 2、按位翻转:将特定为翻转(0→1,1→0)

​ 3、加密解密:与同一个秘钥异或两次可以还原数据。

面试题:不使用临时变量,如何实现两个变量的交换?
提示:交换变量有3种方法:①创建临时变量②使用函数传址方式③使用位运算中的按位异或
这里介绍第三种:

答:无需临时变量交换整数(a = a ^ b; b = a ^ b;a = a ^ b)
易错点:在进行一正一负时,首先搞清楚正数:原码=反码=补码,如果算出来补码首位是0,那就是正数,直补码=反码

如下图所示:

按位左移(<<)

说明:将原操作数的所有二进制位整体 向左移动指定的位数。移位规则为“高舍低补”(高位溢出的二进制位直接丢弃,低位补0)。该规则与存储模式(大/小端)无关,仅取决于移位操作本身。

无符号左移

核心公式:无溢出时,结果等价于操作数∗2移动位数操作数 * 2^{移动位数}操作数2移动位数(溢出后公式失效)

​ 举例:

unsignedchara=3<<3;//结果为24(3*2^3=24)unsignedintb=5<<4;//结果为80(5*2^4=80)

推导:

有符号左移

(注意是通过补码的左移,低位补0,最后在转换为原码)

​ 语法:同上

​ 核心公式:同上

​ 举例:

chara=-3<<3;//结果为-24(-3 * 2 ^ 3 = -24)intb=240<<2;//结果为960(240 * 2 ^2=960)

推导:
8位有符号char:-3<<3

步骤二进制(8 位)说明
原数 -3原码:10000011符号位 1(负),数值位0000011
反码:11111100原码符号位不变,数值位取反
补码:11111101反码 + 1(运算基于补码)
左移 3 位补码:11101000高位溢出丢弃,低位补 0
移位后反码11100111补码 - 1(还原反码)
移位后原码10011000反码符号位不变,数值位取反
结果-24原码10011000对应十进制-24

注意:

1、有符号数的移位基于补码进行(运算过程:原码→反码→补码→移位→反码→原码→结果);

​ 2、若移位后符号位被覆盖(如正数左移后溢出变为负数),公式不在适用,结果由补码规则决定。

反例:

如:char127;左移1位,通过公式计算=127*2^1=254,实际通过补码规则计算结果为-2

按位右移(>>)

说明:将原操作数的所有二进制位整体向右移动指定的位数。移位规则为“高补低舍”(低位溢出的二进制位直接丢失,高位由操作数类型决定补值)。

操作数高位补值规则移位类型
无符号数补0逻辑右移
有符号数补符号位(1补1,0补0)算术右移

注意:大部分编译器(如GCC,Clang,MSVC)对有符号数均采用“算术右移”,极少数特殊平台例外。

核心公式:结果等价于操作数/2移动位数操作数/2^{移动位数}操作数/2移动位数(向下取整)(注意:向下、向上、四舍五入)

无符号右移

举例:

unsignedchara=3>>3;//结果为0(3/2^3=0.375,向下取整为0)

推导:

有符号右移

举例:

chara=-3>>3;//结果为-1(-3/2^3=-0.375,向下取整为-1)

推导:
8位有符号char演示:-3 >> 3:


移位运算完整流程:

原数据→二进制原码→二进制反码→二进制补码→进行移位操作→二进制反码→二进制原码→目标进制结果

C语言运算符的内容到这里就结束了。如果文章里有什么讲得不够清楚或者有错误的地方,还请大家多多担待。欢迎在评论区留言交流,咱们下一章「分支与循环」再见!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/17 1:30:18

LeetCode 摆动序列II题解

LeetCode 摆动序列II题解 题目描述 给定一个整数序列&#xff0c;如果连续数字之间的差严格地交替正负&#xff0c;则称该序列为摆动序列。返回最长摆动子序列的长度。 示例&#xff1a; 输入&#xff1a;nums [1,7,4,9,2,5]输出&#xff1a;6 解题思路 方法&#xff1a;贪心 …

作者头像 李华
网站建设 2026/5/17 1:30:14

Git-IDEA 07 导入变更记录

一、场景 同一个项目的同一分支,自某一时间节点被分别拿去开发不同的功能,现都已开发完成,且都有各自的提交记录,现在需要合并到一起。 二、状态 初始状态: 变更状态1:初始状态下继续开发。 变更状态2:初始状态下复制到别的工作环境继续开发,为区分项目,更名为Test…

作者头像 李华
网站建设 2026/5/17 1:29:43

开源火车模拟器Libre-TrainSim:模块化架构与核心模块实现解析

1. 项目概述&#xff1a;一个开源的火车模拟器能做什么&#xff1f; 如果你和我一样&#xff0c;对火车运行、信号系统或者轨道网络规划有着浓厚的兴趣&#xff0c;但又觉得市面上的商业模拟器要么价格不菲&#xff0c;要么功能受限&#xff0c;那么“Libre-TrainSim”这个项目…

作者头像 李华
网站建设 2026/5/17 1:29:38

Gemini3.1Pro对比GPT4o谁更胜一筹逐项数据实测

做多模型横向对比测试时常用的聚合平台推荐下&#xff1a;库拉KULAAI&#xff08;c.877ai.cn&#xff09;&#xff0c;上面能直接调Gemini 3.1 Pro和GPT-4o等多个主流模型做性能对比。下面进入正题。为什么要拿这两个模型对比Gemini 3.1 Pro是Google DeepMind在2026年2月发布的…

作者头像 李华
网站建设 2026/5/17 1:27:05

GPT-5.5 vs Grok4.3:语言模型实测对比

在人工智能领域&#xff0c;语言模型的核心能力始终是文本理解、生成与推理。对于开发者、产品经理及中小团队而言&#xff0c;选择一款在语言任务上表现稳定、高效的模型&#xff0c;直接关系到应用的用户体验与开发效率。在评估和对比不同语言模型时&#xff0c;可以借助一些…

作者头像 李华
网站建设 2026/5/17 1:26:39

越刷越空?不是自控力太差,是你的大脑“最高权限”丢了

被一块屏幕“遛”着走的人前几天深夜&#xff0c;我和几个以前在老东家一起扛过枪的兄弟&#xff0c;在一个烤串摊喝酒。一桌人&#xff0c;平均四十多岁&#xff0c;平时在公司里不是总监就是合伙人&#xff0c;西装革履&#xff0c;人模狗样。按理说&#xff0c;都算是社会化…

作者头像 李华