目录
- 1.进制转换
- (1)二进制
- (2)八进制
- 八进制位数与权重表
- (3)16进制
- 16进制权重计算表
- (4)进制转换
- 10进制转换成2进制
- 2进制转换成8进制
- 二进制转换成十六进制
- 2.操作符的分类
- 3.原码、反码、补码(了解即可)
- 4.位操作符
- 4.1移位操作符
- `<<`左移操作符
- `>>`右移操作符
- 注意
- 4.2按位操作符
- 按位与`&`
- 按位或`|`
- 按位异或 `^`
- 按位取反`~`
- 4.3复合赋值位操作符
- 4.4位运算符使用技巧与练习
- 5.单目操作符
- 5.1算术类单目操作符
- 5.2逻辑与位操作类单目操作符
- 5.3类型相关单目操作符
- 6.下标访问[]、函数调用()
- 6.1下标访问操作符`[]`
- 6.2函数调用()
- 7.操作符的优先级、结合性
- 8.表达式求值
- (1)整型提升
- (2)整型提升的规则
- 有符号类型提升
- 无符号类型提升
- (3)典例
- 9.算术转换
- (1)基本概念
- (2)代码示例
- 10.补充
- (1)关系操作符
- 需要避免的错误是:多个关系运算符不宜连⽤。
- (2)条件操作符
- (3)短路
- 总结
- 如果你觉得这篇文章对你有帮助,请给文章一个三连支持一下哦
C语言中的操作符用于执行各种运算和操作,主要包括算术操作符、关系操作符、逻辑操作符、位操作符、赋值操作符等。
1.进制转换
在计算机编程的学习中,其实我们经常能听到2进制、8进制、10进制、16进制 这样的讲法,那是什么意思呢?
其实2进制、8进制、10进制、16进制是数值的不同表示形式而已。
比如:数值15的各种进制的表示方式
- 15的2进制:1111
- 15的8进制:17
- 15的10进制:15
- 15的16进制:F
- //16进制的数值之前写:0x
- //8进制的数值之前写:0
(1)二进制
我们先重点讲解一下二进制
十进制图表

二进制图表

(2)八进制
八进制的每一位数字都是由0~7组成,正所谓满8进1
八进制位数与权重表
| 位数 | 权重(8的幂) | 示例值 | 计算方式 |
|---|---|---|---|
| 第1位 | 8^0 = 1 | 1 | 1 * 8^0 |
| 第2位 | 8^1 = 8 | 2 | 2 * 8^1 |
| 第3位 | 8^2 = 64 | 3 | 3 * 8^2 |
| 第4位 | 8^3 = 512 | 4 | 4 * 8^3 |
| 第5位 | 8^4 = 4096 | 5 | 5 * 8^4 |
| 第6位 | 8^5 = 32768 | 6 | 6 * 8^5 |
| 第7位 | 8^6 = 262144 | 7 | 7 * 8^6 |
| 第8位 | 8^7 = 2097152 | 0 | 0 * 8^7 |
(3)16进制
十六进制(Hexadecimal)是一种基数为16的计数系统,使用0-9的数字和A-F的字母来表示数值。
16进制权重计算表
| 16进制位 | 权重(16^n) | 示例值 | 计算方式 |
|---|---|---|---|
| 0 | 16^0 = 1 | 0xF | 15 * 1 |
| 1 | 16^1 = 16 | 0xE | 14 * 16 |
| 2 | 16^2 = 256 | 0xD | 13 * 256 |
| 3 | 16^3 = 4096 | 0xC | 12 * 4096 |
| 4 | 16^4 = 65536 | 0xB | 11 * 65536 |
(4)进制转换
10进制转换成2进制

2进制转换成8进制

二进制转换成十六进制

2.操作符的分类
- 算术操作符: + 、- 、* 、/ 、%
- 移位操作符: << >>
- 位操作符: & | ^
- 赋值操作符: = 、+= 、 -= 、 *= 、 /= 、%= 、<<= 、>>= 、&= 、|= 、^=
- 单⽬操作符: !、++、–、&、*、+、-、~ 、sizeof、(类型)
- 关系操作符: > 、>= 、< 、<= 、 == 、 !=
- 逻辑操作符: && 、||
- 条件操作符: ? :
- 逗号表达式: ,
- 下标引⽤: []
- 函数调⽤: ()
3.原码、反码、补码(了解即可)
整数的2进制表示方法有3种,即原码、反码和补码
有符号整数的三种表示方法均有符号位和数值位两部分,2进制序列中,最⾼位的1位是被当做符号位,剩余的都是数值位。
符号位都是⽤0表示“正”,用1表示“负”。

正整数的原、反、补码都相同
负整数的三种表达方式各不相同
原码: 直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
反码: 将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码: 反码+1就得到补码。
补码得到原码也是可以使⽤:取反,+1的操作。
在计算机中,整数通常以补码存储,但理解补码需要先了解原码和反码。
4.位操作符
C语言中的位操作符用于直接操作整数的二进制位。以下是C语言中常用的位操作符及其功能:
移位操作符的操作数只能是整数,并且是转换成二进制去运行的
4.1移位操作符
<<左移操作符
移位规则:左边抛弃,右边补0
#include <stdio.h>
int main(){
int num = 10;
int n = num << 1;
printf("n = %d\n", n);
printf("num = %d\n", num);
return 0;
}

>>右移操作符
移位规则:首先右移运算分为两种:
- 逻辑右移:左边填充0,右边丢弃
- 算术右移:左边用原来该值的符号位填充,右边丢弃
#include <stdio.h>
int main(){
int num = 10;
int n = num >> 1;
printf("n = %d\n",n);
printf("num = %d\n",num);
return 0;
}

注意
对于移位运算符,不要移动负数位,这个标准是未定义的
4.2按位操作符
&按位与
|按位或
^按位异或
~按位取反
它们的操作数必须是整数
按位与&
两个位都为1时结果为1,否则为0;任何数跟 1 与,结果还是它自己;跟 0 与,结果一定是 0
unsigned char a = 5; // 0101
unsigned char b = 3; // 0011
unsigned char c = a & b; // 0001 (1)
按位或|
两个位中至少有一个为1时结果为1,否则为0
unsigned char a = 5; // 0101
unsigned char b = 3; // 0011
unsigned char c = a | b; // 0111 (7)
按位异或 ^
两个位不同时结果为1,相同时为0
unsigned char a = 5; // 0101
unsigned char b = 3; // 0011
unsigned char c = a ^ b; // 0110 (6)
按位取反~
0变1,1变0
unsigned char a = 5; // 00000101
unsigned char b = ~a; // 11111010 (250)
4.3复合赋值位操作符
C语言还提供了位操作符与赋值操作符结合的复合运算符:
- 按位与赋值 &=
a &= b; // 等价于 a = a & b;
- 按位或赋值 |=
a |= b; // 等价于 a = a | b;
- 按位异或赋值 ^=
a ^= b; // 等价于 a = a ^ b;
- 左移赋值 <<=
a <<= n; // 等价于 a = a << n;
- 右移赋值 >>=
a >>= n; // 等价于 a = a >> n;
4.4位运算符使用技巧与练习
- 技巧
不能创建第三个变量,从而实现两个临时变量的交换
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a = %d b = %d\n", a, b);
return 0;
}
5.单目操作符
单目操作符(Unary Operators)是只需要一个操作数的操作符。
5.1算术类单目操作符
-
正号 +
功能: 保持操作数的正值(通常无实际效果) -
负号 -
功能: 对操作数取负值(算术取反)
-
递增 ++
-
前置递增 ++var
功能: 先增加操作数的值,然后返回增加后的值 -
后置递增 var++
功能: 先返回操作数的值,然后增加操作数的值
- 递减 - -
-
前置递减 --var
功能: 先减少操作数的值,然后返回减少后的值 -
后置递减 var- -
功能: 先返回操作数的值,然后减少操作数的值
5.2逻辑与位操作类单目操作符
- 逻辑非 !
功能: 对操作数进行逻辑取反
操作数类型:标量类型(非零值变为0,零值变为1)
- 按位取反 ~
功能: 对操作数的每一位进行按位取反
操作数类型:整数类型
- 取地址 &
功能: 获取变量的内存地址
操作数类型:左值(可修改的对象)
- 间接引用 *
功能: 通过指针访问指向的值
操作数类型:指针类型
5.3类型相关单目操作符
- 类型转换 (type)
功能: 将操作数显式转换为指定类型
操作数类型:任意可转换的类型
- sizeof 操作符 sizeof
两种形式:
-
sizeof(type):获取类型的大小
-
sizeof expr:获取表达式结果类型的大小
6.下标访问[]、函数调用()
这一节的内容跟
数组和指针的关系很大
6.1下标访问操作符[]
操作数: 一个数组名 + 一个索引值[下标
int arr[10];//创建数组
arr[9] = 10;//实⽤下标引⽤操作符。
[ ]的两个操作数是arr和9
6.2函数调用()
接受⼀个或者多个操作数:第⼀个操作数是函数名,剩余的操作数就是传递给函数的参数。
#include <stdio.h>
void test1()
{
printf("hehe\n");
}
void test2(const char *str)
{
printf("%s\n", str);
}
int main()
{
test1(); //这⾥的()就是作为函数调⽤操作符。
test2("hello bit.");//这⾥的()就是函数调⽤操作符。
return 0;
}
7.操作符的优先级、结合性
- 优先级
优先级指的是,如果⼀个表达式包含多个运算符,哪个运算符应该优先执⾏。各种运算符的优先级是
不⼀样的。
3 + 4 * 5;
上⾯⽰例中,表达式 3 + 4 * 5⾥⾯既有加法运算符( +),⼜有乘法运算符(*)。由于乘法
的优先级⾼于加法,所以会先计算4 * 5,⽽不是先计算3 + 4。
- 结合性
如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符是左结合,还是右结合,决定执⾏顺序。⼤部分运算符是左结合(从左到右执行),少数运算符是右结合(从右到左执⾏),⽐如赋值运算符( = )。
5 * 6 / 2;
上⾯⽰例中, * 和 / 的优先级相同,它们都是左结合运算符,所以从左到右执⾏,先计算 5 * 6 ,
再计算 / 2 。
运算符的优先级顺序很多,下⾯是部分运算符的优先级顺序(按照优先级从⾼到低排列),建议⼤概
记住这些操作符的优先级就⾏,其他操作符在使⽤的时候查看下⾯表格就可以了。
-
圆括号( () )
-
⾃增运算符( ++ ),⾃减运算符( – )
-
单⽬运算符( + 和 - )
-
乘法( * ),除法( / )
-
加法( + ),减法( - )
-
关系运算符( < 、 > 等)
-
赋值运算符( = )
由于圆括号的优先级最⾼,可以使⽤它改变其他运算符的优先级。
8.表达式求值
(1)整型提升
整型提升(integer promotion) 是指当表达式中使用比int类型小的整型(如char、short)时,这些值会被自动转换为
int或unsigned int类型后再参与运算的规则。
(2)整型提升的规则
有符号类型提升
如果原始类型的所有值都能用int表示,则提升为int,否则提升为unsigned int
-
char → int
-
short → int
无符号类型提升
如果原始类型的所有值都能用int表示,则提升为int,否则提升为unsigned int
-
unsigned char → int (如果int能表示所有unsigned char值)
-
unsigned short → int (如果int能表示所有unsigned short值)
(3)典例
#include <stdio.h>
int main() {
char a = 120;
char b = 20;
char c = a + b;
printf("%d\n", c); // 输出 -116
return 0;
}
为什么最后c的值是-116呢
这个问题涉及到 C语言中的整型提升、溢出和补码表示
- char 的存储范围
-
在大多数C实现中,char 默认是 有符号的(signed char),范围是 -128 ~ 127。
-
120 和 20 都在这个范围内,所以 a 和 b 的初始值是正确的。
-
但 120 + 20 = 140,超过了 char 的最大值 127,导致 溢出(overflow)。
- 整型提升(Integer Promotion)
-
在计算 a + b 时,C语言会先进行 整型提升:
-
a 和 b 都是 char 类型,比 int 小,所以会被提升为 int 类型。
提升后:
a(120)→ int 类型的 120
b(20)→ int 类型的 20
计算 a + b 得到 140(仍然是 int 类型)。
- 赋值回 char 时发生截断
虽然 a + b 的结果是 140(int 类型),但我们要把它赋值给 char c,而 char 只能存储 -128 ~ 127。
所以 140 会被 截断(truncated) 以适应 char 的存储范围。
如何计算截断后的值?
140超出char的表示范围,计算方式如下:
-
char 是 8 位有符号整数,能表示的最大值是 127(0b01111111)。
-
140 的二进制表示是 0b10001100(128 + 8 + 4 = 140)。
-
由于 char 是 有符号的,最高位是符号位:
- 0b10001100 被解释为 补码(为什么是补码前面有讲过):
最高位 1 表示负数。
- 计算其补码对应的十进制值:
取反:0b10001100 → 0b01110011
加 1:0b01110011 + 1 = 0b01110100(116)
所以 0b10001100 表示 -116。
9.算术转换
由于某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型
(1)基本概念
-
隐式转换:编译器自动进行的类型转换,无需程序员显式指定
-
显式转换:程序员通过强制类型转换运算符明确指定的转换
(2)代码示例
int i = 5;
float f = 3.14;
double d = i + f; // i先转换为float,相加后再转换为double
unsigned int u = 10;
int s = -5;
long result = u + s; // s转换为unsigned int,可能导致意外结果
10.补充
这里我们把操作符一些残枝末节给收拾干净,避免给以后的学习留下盲点
(1)关系操作符
C 语⾔⽤于⽐较的表达式,称为 “关系表达式”,⾥⾯使⽤的运算符就称
为“关系运算符”
>⼤于运算符<⼩于运算符>=⼤于等于运算符<=⼩于等于运算符==相等运算符!=不相等运算符
关系表达式通常返回 0 或 1 ,表⽰真假。
注意: 相等运算符==与赋值运算符=是两个不⼀样的运算符,不要混淆。
为了防止出现这种错误,有的程序员喜欢将变量写在等号的右边。
if (3 == x) ... 1
这样的话,如果把 == 误写成 = ,编译器就会报错。
/* 报错 */
if (3 = x) ...
需要避免的错误是:多个关系运算符不宜连⽤。
i < j < k
上⾯示例中,连续使用两个小于运算符。这是合法表达式,不会报错,但是通常达不到想要的结果,
实际执行的是下面的表达式。
(i < j) < k 1
上⾯式⼦中, i < j 返回 0 或 1 ,所以最终是 0 或 1 与变量 k 进⾏⽐较。
如果想要判断变量 j的值是否在 i 和 k 之间,应该使⽤下⾯的写法。
i < j && j < k
(2)条件操作符
条件操作符也叫三⽬操作符,需要接受三个操作数的,形式如下:
exp1 ? exp2 : exp3
条件操作符的计算逻辑是:
如果 exp1 为真, exp2 计算,计算的结果是整个表达式的结果;
如果exp1 为假, exp3 计算,计算的结果是整个表达式的结果。
(3)短路
C语⾔逻辑运算符还有⼀个特点,它总是先对左侧的表达式求值,再对右边的表达式求值,这个顺序是保证的。
如果左边的表达式满⾜逻辑运算符的条件,就不再对右边的表达式求值。这种情况称为短路。
if(month >= 3 && month <= 5)
表达式中&& 的左操作数是 month >= 3 ,右操作数是 month <= 5 ,当左操作数 month >= 3 的结果是0的时候,即使不判断 month <= 5 ,整个表达式的结果也是0(不是春季)。
所以,对于&&操作符来说,左边操作数的结果是0的时候,右边操作数就不再执⾏。
- 对于 || 操作符是怎么样呢?我们结合前⾯的代码:
if(month == 12 || month == 1 || month == 2) 1
如果month == 12,则不⽤再判断month是否等于1或者2,整个表达式的结果也是1。
所以,||操作符的左操作数的结果不为0时,就⽆需执⾏右操作数。
像这种仅仅根据左操作数的结果就能知道整个表达式的结果,不再对右操作数进⾏计算的运算称为短路求值。
总结
由于这一章的很多内容小编已经在前面讲过了,所以有些内容会一笔带过
并且这一章的内容只是给C语言的分支与循环的程序练习作下铺垫
小编提醒 由于操作符的繁杂和多样性,所以在编程时候尽量不要写太乱的代码,以免程序发生错乱
如果你觉得这篇文章对你有帮助,请给文章一个三连支持一下哦







