前言
学 C 语言时,总绕不开 "进制怎么转""移位操作符怎么用""表达式为啥这么算" 这些问题 ------ 它们不算多高深,但都是写代码、调 Bug 的基础。
比如写个简单的位运算,若搞不清二进制和十进制的转换逻辑,很容易算错结果;处理表达式时,要是忽略了整型提升的规则,可能会碰到莫名其妙的运行错误。
这篇就整理了自己对进制转换、移位操作符、算数转换这些内容的理解,不求讲得多深,只希望把这些基础知识点理清楚,方便自己回头翻,也给刚入门的朋友做个参考。
目录
[1、2进制 ---> 10进制](#1、2进制 —> 10进制)
[2、10进制 ---> 2进制](#2、10进制 —> 2进制)
[3、2进制 ---> 8进制](#3、2进制 —> 8进制)
[4、8进制 ---> 2进制](#4、8进制 —> 2进制)
[5、2进制 ---> 16进制](#5、2进制 —> 16进制)
[6、16进制 ---> 2进制](#6、16进制 —> 2进制)
[1、<< 左移操作符](#1、<< 左移操作符)
[2、>> 右移操作符](#2、>> 右移操作符)
一、2进制与进制转换
咱日常说的 "二进制 / 八进制 / 十进制 / 十六进制",其实就是数字的 "不同穿搭"------ 本质都是同一个数,换身衣服罢了~
比如数字 "15" 的 "穿搭秀":
二进制款:1111(主打一个极简,就 0 和 1 俩元素)
八进制款:17(穿它得加个前缀0,不然认不出来)
十进制款:15(咱生活里最常穿的 "基础款")
十六进制款:F(拽哥款,前缀得配0x才够范儿)
**二进制的 "穿衣规则"**别觉得它高冷,其实和十进制是 "亲戚":
十进制:凑够 10 个就升级(满 10 进 1),元素是 0~9
二进制:凑够 2 个就跑路(满 2 进 1),元素只有 0 和 1
所以像1101这种 "01 串串",就是二进制本进制啦~
1、2进制 ---> 10进制
其实10进制的123表⽰的值是⼀百⼆⼗三,为什么是这个值呢?其实10进制的每⼀位是有权重的,
10进制的数字从右向左是个位、⼗位、百位....,分别每⼀位的权重是 10^0 , 10^1 , 10^2 ...
如下图:
10进制123每一位权重的理解
2进制和10进制是类似的,只不过2进制的每⼀位的权重,从右向左是: 2^0 , 2^1 , 2^2 ...
如果是2进制的1101,该怎么理解呢?
2进制1101每一位的权重理解
你看,二进制 1101这么一拆,每一位对应 "2 的次方面额",乘完一加就得到 13 啦!所以二进制 1101
转成十进制,就是咱们算出来的 13------ 这招 "按位拆算",就是二进制转十进制的万能小妙招~
2、10进制 ---> 2进制

这招主打一个 "拆了再拼":把十进制数当成 "待拆分的大蛋糕",每次用 2 除它,把剩下的 "余数小块" 记下来,直到除到 0 为止。
比如转 125:
- 拿 125÷2,商 62,余 1 → 记个 1
- 62÷2,商 31,余 0 → 记个 0
- 31÷2,商 15,余 1 → 记个 1......(就这么一直除,一直记余数)最后把记下来的余数从下往上倒着读,就是 1111101------ 这就是 125 对应的二进制啦!
简单说就是:除 2 取余,余数倒排,搞定~
3、2进制 ---> 8进制
八进制的特点:每一位是 0~7,而 0~7 的数字转成二进制,最多只需要 3 位(比如 7 的二进制是 111)。
转换规则 :从二进制的右边低位开始,每 3 位分为一组,每组转成对应的八进制数;不足 3 位的组直接换算。

4、8进制 ---> 2进制
核心逻辑:八进制的每一位(0~7),刚好对应 "3 位二进制数"(比如八进制的 7 对应二进制 111),所以转的时候直接 "1 位八进制→3 位二进制" 展开就行。
操作步骤:
- 把八进制的每一位数字,单独转成对应的 3 位二进制数;
- 要是某一位转成二进制不足 3 位,就在左边补 0 凑够 3 位;
- 把所有位转好的二进制数连起来,就是最终结果。
8进制0153转2进制
5、2进制 ---> 16进制
核心逻辑:十六进制每位是 0~9、a~f,这些数字转成二进制最多需要 4 位(比如 f 的二进制是 1111),因此转换时按 "4 位二进制→1 位十六进制" 分组即可。
转换规则:从二进制的右边低位开始,每 4 位分为一组,每组换算成对应的十六进制位;剩余不足 4 位的组直接换算。

6、16进制 ---> 2进制
核心逻辑:十六进制的每一位(0~9、a~f),刚好对应 "4 位二进制数"(比如 16 进制的 f 对应二进制 1111),所以转的时候直接 "1 位 16 进制→4 位二进制" 展开即可。
操作步骤:
- 把 16 进制的每一位数字 / 字母,单独转成对应的 4 位二进制数;
- 若某一位转成二进制不足 4 位,在左边补 0 凑够 4 位;
- 将所有位转好的二进制数连起来,就是最终结果。 核心逻辑:十六进制的每一位(0~9、a~f),刚好对应 "4 位二进制数"(比如 16 进制的 f 对应二进制 1111),所以转的时候直接 "1 位 16 进制→4 位二进制" 展开即可。
16进制0xA3转2进制
【2进制、8进制、16进制转10进制总结】
| 进制转换类型 | 基数 | 位权规则(从右往左,第 k 位) | 核心计算方式 |
|---|---|---|---|
| 二进制→十进制 | 2 | 2^(k-1) | 每位 ×2ⁿ 相加 |
| 八进制→十进制 | 8 | 8^(k-1) | 每位 ×8ⁿ 相加 |
| 十六进制→十进制 | 16 | 16^(k-1) | 每位 ×16ⁿ 相加 |
二、原码、反码、补码
整数(有符号整型才用原反补表示)的二进制表示有三种方式:原码、反码、补码。
【通用规则】
有符号整数的这三种表示,都分成符号位 和数值位两部分:
- 二进制的最高位 是符号位:
0代表 "正",1代表 "负"; - 剩下的位是数值位,用来表示具体数值。
【正整数的表示】
正整数的原码、反码、补码完全一样 ,直接把数值转成二进制,最高位补0(表示正数)就行。比如 + 5(假设是 8 位):
- 原码 / 反码 / 补码:
0000 0101
【负整数的表示】
负整数的原、反、补码各不相同,得按步骤转换:
-
原码 :把数值转成二进制,最高位补
1(表示负数)。比如 - 5(8 位):1000 0101 -
反码 :原码的符号位不变 ,数值位按位取反(0 变 1,1 变 0)。比如 - 5 的反码:
1111 1010(符号位1不变,数值位000 0101取反成111 1010) -
补码 :反码的基础上加 1 。比如 - 5 的补码:
1111 1011(反码1111 1010+1 =1111 1011)
【补码转原码】
如果已知补码,想转原码,步骤是:补码按位取反 ,然后加 1 (和 "原码转补码" 的操作一样)。比如补码1111 1011(对应 - 5):
- 取反:
1000 0100 - 加 1:
1000 0101(刚好是 - 5 的原码)
计算机里所有有符号整数的运算(不管是加还是减),全程都是用补码来算的。
这是因为 CPU 硬件只有加法器,而补码能把减法 "伪装" 成加法 ------ 比如算3-2,实际会变成3 + (-2的补码),用加法就能得到正确结果。

显而易见,用补码计算的结果是正确的 ------ 不过这只针对有符号整数;如果是无符号整数,直接用二进制数值计算即可。
三、移位操作符
1、<< 左移操作符
移位规则:左边抛弃、右边补0
左移操作符演示

2、>> 右移操作符
移位规则:⾸先右移运算分两种:
- 逻辑右移:左边⽤0填充,右边丢弃
- 算术右移:左边⽤原该值的符号位填充,右边丢弃
逻辑右移演示
算术右移演示

通过在 VS 中的实际运行结果可以看出,C 语言中带符号整数的右移操作符(>>),底层遵循的是算术右移规则。
警告⚠️:对于移位运算符,不要移动负数位,这个是标准未定义的。
cpp
int num = 10;
num>>-1;//error
四、整型提升
关于整型提升,其实是 C 语言里小整型参与运算的 "隐形规则"------ 因为 CPU 的整型运算器默认是int长度,所以char、short这类比int短的类型,在做加减、位运算前,都会先转成int(或unsigned int),这个过程就叫整型提升。
它的核心逻辑很简单:
1、有符号整数提升是按照变量的数据类型的符号位来提升的
2、⽆符号整数提升,⾼位补0
整型提升演示
注意,提升只是运算时的临时转换,运算结束后如果存回小整型变量,结果会被截断回原类型的长度。
五、算术转换
当运算符的两个操作数类型不同时,不能直接运算 ------ 得先把类型 "等级低" 的那个,转换成 "等级高" 的类型,这个转换规则就是 "寻常算术转换"。
它的核心是一个 "类型优先级层级表"(等级越靠前,优先级越高):
cpp
long double
double
float
unsigned long int
long int
unsigned int
int
转换逻辑很简单:
看两个操作数的类型在层级表里的位置 ------把 "排名靠后"(优先级低)的类型,转换成 "排名靠前"(优先级高)的类型,然后再运算。
总结:
算术转换的目的是 "让不同类型的操作数统一成同一种高优先级类型",避免运算出错 ------ 本质是按 "类型优先级" 向上对齐。
【整数类型参数表】
| 类型分类 | 位数 (bit) | 取值范围(十进制) | 最大值公式 |
|---|---|---|---|
| 无符号整数 | 8 | 0 ~ 255 | 2^8 - 1 |
| 16 | 0 ~ 65535 | 2^16 - 1 | |
| 32 | 0 ~ 4294967295 | 2^32 - 1 | |
| 64 | 0 ~ 18446744073709551615 | 2^64 - 1 | |
| 有符号整数(补码) | 8 | -128 ~ 127 | 2^7 - 1 |
| 16 | -32768 ~ 32767 | 2^15 - 1 | |
| 32 | -2147483648 ~ 2147483647 | 2^31 - 1 | |
| 64 | -9223372036854775808 ~ 9223372036854775807 | 2^63 - 1 |
核心规则:
无符号整数:n 位全部用于表示数值,取值范围是 0 ~ 2^n - 1(无符号位)。
有符号整数(补码):最高位是符号位(1 表示负数,0 表示正数),取值范围是 -2^(n-1) ~ 2^(n-1) - 1 (比无符号少 1 位数值位)。
