完整且详细的C语言教程,从入门到精通(3)--C语言的运算符(算术、关系、逻辑、位运算、赋值等运算符)
2026/7/4 3:16:19 网站建设 项目流程

你们好,我是一名嵌入式工程师。我正在持续更新《嵌入式工程师的C语言实战》系列教程,目前已更新4篇。如果你也在学习嵌入式,欢迎点个关注,我们一起从零到一。

文章目录

  • 前言
  • 一、算术运算符(Arithmetic Operators)
  • 二、关系运算符(Relational Operators)
  • 三、逻辑运算符(Logical Operators)
  • 四、位运算符(Bitwise Operators)
  • 五、赋值运算符(Assignment Operators)
  • 六、自增自减运算符(Increment/Decrement Operators)
  • 七、条件运算符(Conditional Operator / 三目运算符)
  • 八、逗号运算符(Comma Operator)
  • 九、sizeof 运算符
  • 十、地址与间接访问运算符
  • 十一、成员访问运算符
  • 十二、其他运算符
  • 十三、运算符优先级速查表(从高到低)
  • 如果这篇文章对你有帮助,欢迎点赞、收藏、关注,主播是一个马上粉丝量超1个的嵌入式内容主播。谢谢!

前言

C语言的运算符非常丰富,涵盖了算术、关系、逻辑、位运算、赋值等各个领域。下面为你系统性地分类整理,并附上详细的说明和示例。

C语言的运算符覆盖了从基础算术到内存操作的方方面面,按功能可归纳为

分类运算符
算术类+ - * / % ++ –
比较类> < >= <= == !=
逻辑类&& || !
位操作类& | ^ ~ << >>
赋值类= 及其复合形式
地址与访问类& * . ->
其他sizeof ?: , () [] (type)

一、算术运算符(Arithmetic Operators)

用于执行基本的数学运算。

运算符含义示例说明
+加法a + b两数相加
-减法a - b两数相减
*乘法a * b两数相乘
/除法a / b两数相除(整数除法会截断)
%取模(求余)a % b返回两数相除的余数(仅用于整数)
#include<stdio.h>intmain(){inta=10,b=3;printf("10 + 3 = %d\n",a+b);// 13printf("10 - 3 = %d\n",a-b);// 7printf("10 * 3 = %d\n",a*b);// 30printf("10 / 3 = %d\n",a/b);// 3(整数除法截断)printf("10 %% 3 = %d\n",a%b);// 1(余数)return0;}

二、关系运算符(Relational Operators)

用于比较两个值的大小关系,返回 1(真)或 0(假)。

运算符含义示例说明
>大于a > ba 是否大于 b
<小于a < ba 是否小于 b
>=大于等于a >= ba 是否大于等于 b
<=小于等于a <= ba 是否小于等于 b
==等于a == ba 是否等于 b(注意是两个等号)
!=不等于a != ba 是否不等于 b
inta=5,b=5;printf("%d\n",a==b);// 输出 1(真)printf("%d\n",a>b);// 输出 0(假)

常见错误:把 == 写成 =,会导致赋值而非比较。

三、逻辑运算符(Logical Operators)

用于组合多个条件,返回 1(真)或 0(假)。

运算符含义示例说明
&&逻辑与a && b两个条件都为真时才为真(短路求值)
||逻辑或a || b至少一个条件为真时为真(短路求值)
!逻辑非!a取反(真变假,假变真)
intage=20,score=85;if(age>=18&&score>=60){printf("成年且及格\n");}if(!(age<18)){printf("已成年\n");}

短路求值示例

intx=0;if(x!=0&&10/x>1){// 因为 x != 0 为假,短路,不会执行 10 / x,避免除零错误// ...}

四、位运算符(Bitwise Operators)

用于对整数的二进制位进行操作。

运算符含义示例说明
&按位与a & b对应位都为 1 时结果为 1
|按位或a | b对应位至少一个为 1 时结果为 1
^按位异或a ^ b对应位不同时为 1,相同时为 0
~按位取反~a所有位取反(0变1,1变0)
<<左移a << n所有位左移 n 位,低位补 0
>>右移a >> n所有位右移 n 位(符号位取决于类型)
unsignedchara=0b1100;// 12unsignedcharb=0b1010;// 10printf("a & b = %d\n",a&b);// 8 (0b1000)printf("a | b = %d\n",a|b);// 14 (0b1110)printf("a ^ b = %d\n",a^b);// 6 (0b0110)printf("~a = %d\n",~a);// 243 (0b11110011)printf("a << 2 = %d\n",a<<2);// 48 (0b110000)printf("a >> 2 = %d\n",a>>2);// 3 (0b0011)

五、赋值运算符(Assignment Operators)

用于给变量赋值,其中复合赋值运算符结合了运算和赋值。

运算符含义示例等价于
=简单赋值a = 10a = 10
+=加后赋值a += 5a = a + 5
-=减后赋值a -= 5a = a - 5
*=乘后赋值a *= 5a = a * 5
/=除后赋值a /= 5a = a / 5
%=取模后赋值a %= 5a = a % 5
&=按位与后赋值a &= 5a = a & 5
|=按位或后赋值a |= 5a = a | 5
^=按位异或后赋值a ^= 5a = a ^ 5
<<=左移后赋值a <<= 2a = a << 2
>>=右移后赋值a >>= 2a = a >> 2
intx=10;x+=5;// x = 15x*=2;// x = 30printf("%d\n",x);

六、自增自减运算符(Increment/Decrement Operators)

用于将变量的值增加或减少 1。

运算符含义示例说明
++自增a++ 或 ++a变量加 1
自减a-- 或 --a变量减 1

前缀 vs 后缀
前缀(++a):先自增,再使用变量的值。
后缀(a++):先使用变量的值,再自增。

inta=5;intb=++a;// a 变为 6,b 被赋值为 6intc=a--;// c 被赋值为 6(使用 a 的当前值),然后 a 变为 5printf("a=%d, b=%d, c=%d\n",a,b,c);// a=5, b=6, c=6

七、条件运算符(Conditional Operator / 三目运算符)

唯一的三目运算符,用于简化 if-else。

运算符语法说明
?:条件 ? 表达式1 : 表达式2若条件为真,取表达式1的值,否则取表达式2的值
intage=20;constchar*status=(age>=18)?"成年":"未成年";printf("%s\n",status);// 输出:成年

八、逗号运算符(Comma Operator)

用于将多个表达式串联成一个表达式,按从左到右的顺序执行,整个表达式的值是最右边表达式的值。

inta,b;a=(b=3,b+2);// 先执行 b=3,然后执行 b+2=5,整个表达式值为 5printf("a=%d, b=%d\n",a,b);// a=5, b=3

九、sizeof 运算符

sizeof 是 C/C++ 中一个编译时的一元运算符,它用于计算一个类型或变量在内存中占用的字节数。它既不是函数(尽管写法像),也不是关键字,而是一个运算符。

9.1 sizeof 的核心作用
获取类型大小:查询基本类型(int, double)或自定义类型(struct, enum)的存储大小。
获取变量大小:获取任何变量或表达式结果的大小。
辅助内存分配:在 malloc、calloc 或 new 时,用于计算需要分配的内存大小。
计算数组元素个数:通过 sizeof(array) / sizeof(array[0]) 得到数组长度。

9.2 sizeof 的常见用法

#include<stdio.h>intmain(){// 1. 作用在类型上printf("int 大小: %zu\n",sizeof(int));// 通常 4printf("double 大小: %zu\n",sizeof(double));// 通常 8// 2. 作用在变量上inta=10;doubled=3.14;printf("变量 a 大小: %zu\n",sizeof(a));// 4printf("变量 d 大小: %zu\n",sizeofd);// 8(括号可省略)// 3. 计算数组长度intarr[10]={0};size_tlen=sizeof(arr)/sizeof(arr[0]);// 10/1 = 10printf("数组元素个数: %zu\n",len);// 4. 动态内存分配int*p=(int*)malloc(10*sizeof(int));// 分配 10 个 int 的空间if(p)free(p);return0;}

9.3 sizeof 的注意事项
9.3.1 sizeof 是编译时求值:sizeof 的结果在编译阶段就确定了,因此它不关心括号内的内容(变长数组除外)。

括号内是 0 还是 100,对结果没有任何影响。

#include<stdio.h>intmain(){intx=10;// 这两种写法结果完全相同,都是 sizeof(int)printf("sizeof(x) = %zu\n",sizeof(x));// 输出 4(假设 int 为 4 字节)printf("sizeof(x+5) = %zu\n",sizeof(x+5));// 输出 4(表达式类型是 int)return0;}

关键点:sizeof(x+5) 不会计算 x+5 的值,它只推导出 (x+5) 的类型是 int,所以结果是 4。

区别对待:变长数组(VLA)是唯一的例外
只有变长数组(VLA) 的 sizeof 是在运行时求值的。这时,编译器必须知道其具体长度,因此 sizeof 会“关心”括号内的内容(即数组的长度表达式)。

#include<stdio.h>intmain(){intn=5;intvla[n];// 变长数组(VLA)printf("sizeof(vla) = %zu\n",sizeof(vla));// 输出 20(5*4),在运行时计算printf("sizeof(vla) = %zu\n",sizeof(int[n]));// 输出 20,也是运行时求值return0;}

9.3.2 对数组和指针的区分

intarr[10];int*ptr=arr;printf("数组: %zu\n",sizeof(arr));// 40 (10*4)printf("指针: %zu\n",sizeof(ptr));// 8 (64位系统)

结构体对齐填充:sizeof 结构体返回的是包含内存对齐填充后的总大小,可能大于成员大小之和。

9.4 sizeof 与 strlen 的区别
这是初学者最容易混淆的两个概念。sizeof 是运算符,strlen 是函数,它们有本质区别。

特性sizeofstrlen
本质运算符(编译时求值)函数(运行时求值)
计算对象类型、变量、任何表达式必须以 ‘\0’ 结尾的字符串
计算内容在内存中占用的总字节数字符串中 ‘\0’ 之前的字符个数
是否包含结尾符包含(数组或字符串字面量)不包含
参数要求任何类型必须是 char* 类型

示例对比

#include<stdio.h>#include<string.h>intmain(){charstr[]="Hello";// 实际存储: H e l l o \0printf("sizeof(str) = %zu\n",sizeof(str));// 输出 6 (包含 '\0')printf("strlen(str) = %zu\n",strlen(str));// 输出 5 (不包含 '\0')// 对指针使用 sizeof 与 strlen 的区别char*p="Hello";printf("sizeof(p) = %zu\n",sizeof(p));// 输出 8 (指针本身大小)printf("strlen(p) = %zu\n",strlen(p));// 输出 5 (字符串长度)}

总结
sizeof:问的是“这个类型或变量在内存里占多大的空间?”
strlen:问的是“从字符串开头到第一个 ‘\0’ 之前有多少个字符?”

十、地址与间接访问运算符

运算符含义示例说明
&取地址&var获取变量的内存地址
*解引用(间接访问)*ptr访问指针指向的内存内容
intx=10;int*p=&x;// p 存储 x 的地址printf("x 的值: %d\n",*p);// 通过指针访问 x 的值,输出 10*p=20;// 通过指针修改 x 的值printf("x 的新值: %d\n",x);// 输出 20

十一、成员访问运算符

用于访问结构体或联合体的成员。

运算符含义示例说明
.直接成员访问struct_var.member通过结构体变量访问成员
->间接成员访问struct_ptr->member通过结构体指针访问成员(等价于 (*ptr).member)
structPoint{intx,y;};structPointp={10,20};structPoint*ptr=&p;printf("%d\n",p.x);// 10printf("%d\n",ptr->y);// 20(等价于 (*ptr).y)

十二、其他运算符

运算符含义示例说明
()函数调用func(a, b)调用函数
[]下标访问arr[3]访问数组元素
(type)强制类型转换(float)3将值转换为指定类型
floatf=(float)10/3;// 强制将 10 转为 float,结果 3.333intarr[5]={1,2,3,4,5};intval=arr[2];// val = 3

十三、运算符优先级速查表(从高到低)

优先级运算符结合性
最高() [] -> .从左到右
! ~ ++ – - + * & (type) sizeof从右到左(单目)
* / %从左到右
+ -从左到右
<< >>从左到右
< <= > >=从左到右
== !=从左到右
&从左到右
^从左到右
|从左到右
&&从左到右
||从左到右
?:从右到左(三目)
= += -= *= /= %= &= ^= |= <<= >>=从右到左
最低,从左到右

建议:不必死记优先级表,在复杂表达式中多用括号 () 来明确运算顺序,既能提高可读性,又能避免优先级错误。

如果这篇文章对你有帮助,欢迎点赞、收藏、关注,主播是一个马上粉丝量超1个的嵌入式内容主播。谢谢!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询