程序是怎样跑起来的?精读第2章:二进制如何支撑整个计算机世界
很多人学编程是从“hello world”开始的但真问一句“计算机凭什么认识这些代码”八成要卡壳。我看了好几本入门书直到遇到《程序是怎样跑起来的》这本才把脑子里那些零散概念串成线。这本书第1章讲CPU的工作方式第2章就直接捅到最底层——数据是用二进制数表示的。千万别小看这一章它是整个计算机知识体系的承重墙不理解二进制后面的内存寻址、文件格式、网络协议、图像编码学起来全是隔着一层纸。这篇博客把第2章的核心内容和我这些年实际用到的东西揉在一起做一份能直接落地的“精读版总述”适合正在学基础、准备补计算机功底的开发者。1. 为什么程序偏偏要用二进制1.1 不用十进制是物理电路的现实约束很多人第一次听说“程序里所有数据都是0和1”时都会问一句为什么不用十进制明明人类从小就习惯十个数字计算机要是能直接处理0到9不是更省事吗答案不在数学里在硬件里。计算机的运算核心是CPUCPU由数以亿计的晶体管构成。晶体管这东西本质上就是一个受电压控制的开关只有两种稳定工作状态导通或者截止。所谓“导通”就是电路通了对应高电平所谓“截止”就是电路断了对应低电平。要做数字电路最自然、最可靠的方式就是拿这两种状态来编码信息高电平记作1低电平记作0。如果非要让电路直接表示十进制的10个数字就得把电压划分成10个不同的区间每个区间对应一个数字。这在理论上能实现但在工程上是一场噩梦。一来芯片内部电磁干扰不可避免电压会波动10个区间的容错空间太小某一位电压稍微偏一点机器就读错了二来电路设计会变得极其复杂一个十进制加法器的电路复杂度比二进制加法器高出几个量级。二进制虽然“啰嗦”数字位数长但胜在抗干扰、易实现、可靠这就是工业界的共识。你可以把计算机里的二进制理解成用灯泡的亮灭来传递信息亮是1灭是0简单直接永远不会看错。1.2 位置计数法二进制没那么反人类当然光知道“为什么用二进制”还不够更关键的是得会用。很多人在进制转换上栽跟头本质是没有理解“位置计数法”这个底层规律。十进制里的“123”为什么是一百二十三其实它表示的是1×10² 2×10¹ 3×10⁰每一位的权重是10的幂。二进制完全同理只是把底数换成2比如二进制1101展开就是1×2³ 1×2² 0×2¹ 1×2⁰ 8 4 0 1 13。所以二进制不是“另一种数学”只是换了一套权重规则。我教新手转换时最推荐的办法不是背公式而是记住下面这串权重数字位权2⁷2⁶2⁵2⁴2³2²2¹2⁰十进制值1286432168421把任何一个十进制数拆成这8个数之和然后对应位置填1其余填0就得到8位二进制。比如37 32 4 1那么就是00100101再比如200 128 64 8对应11001000。这个方法比“不断除以2取余数”直观得多心算就能完成我面试别人时也经常用这招试探基本功。2. 数据与程序底层只有0和1在流动2.1 数值、字符、图像、声音全在做同一件事理解了二进制本身下一个推演就很自然计算机里的一切数据不管看起来是数字、英文、汉字还是一张照片、一段音乐落到内存里统统都是二进制。区别只在于“解释方式”。拿常见的类型举例整数42在32位环境下内存里是00000000 00000000 00000000 00101010。字符AASCII码是65二进制就是01000001。一个像素点用RGB三通道表示每个通道占8位三个字节就能描述一个颜色例如纯红色是11111111 00000000 00000000。一段CD音质的音频每秒钟要采样44100次每次采样的幅度用16位整数记录这就是量化。你应该已经发现了同样是8个比特位你可以把它解释成无符号整数、有符号整数、ASCII字符甚至是一个很小的小数。同一个字节0x41当整数看是65当字符看是A当浮点数的一部分看又是另一个数。所谓数据类型本质上就是“给一段0/1序列规定解读规则”。这个认知特别重要很多程序出错都是因为同一个字节被两种不同规则解读了。2.2 程序本体就是二进制指令序列除了数据程序本身也是二进制。你写的C语言、Python代码在运行前最终都要变成CPU能直接执行的机器语言指令而机器语言就是一堆二进制数字。x86架构里把数字1写入eax寄存器的一条指令机器码可能是B8 01 00 00 00在内存里就是11111000 00000001 00000000 00000000 00000000。编译器、汇编器干的事情本质上是把一个人类可读的文本文件转换成“CPU可读”的二进制文件。这个文件存储着一连串指令和数据加载到内存后CPU按照程序计数器指示的地址一条条取出、解码、执行。这就是“程序”能跑起来的真相。所以我一直跟新人强调先理解二进制再谈上层框架。因为不管你用React还是Spring Boot最终产物在执行时走的还是底层那套取指令、解码、执行的流程。框架换得再勤地基永远是那些0和1。3. 第2章精读四个必须吃透的核心知识点3.1 位、字节与数据表示范围《程序是怎样跑起来的》第2章花了大量篇幅讲数据范围这是很多人囫囵吞枣的地方。先说两个单位1位bit只能表示0或18位组成1字节byte这是计算机存储的基本单位。8位能表示多少种状态2⁸ 256种。如果你把这些状态全部当作无符号整数就能表示0到255如果当作有符号整数就涉及负数表示法通常范围是-128到127。为什么是-128到127而不是-127到128这里藏着补码的伏笔下面再说。常见数据类型范围请直接记这张表类型字节数无符号范围有符号范围char10 ~ 255-128 ~ 127short20 ~ 65535-32768 ~ 32767int40 ~ 4294967295-2147483648 ~ 2147483647long long8超大更大我想让你盯住一个现象给char类型赋127加1之后就变成-128给unsigned char赋255加1之后就变成0。这不是编译器bug而是位模式的回绕——二进制数字在有限位数内“溢出”了。127的二进制是01111111加1变成10000000按有符号解释就是-128255的二进制是11111111加1变成100000000但char只有8位最高位的1丢失只剩00000000于是变回0。3.2 补码负数为什么要用补码表示有符号数的负数表示是这一章最容易劝退人的地方。我当年学的时候也很懵为什么不能干脆用最高位当符号位把10000011看成“-3”理论上可以但硬件会变得很复杂因为加减法得分别处理正数和负数。补码的巧妙之处在于它让减法变成了加法。8位补码的定义是一个数的负数等于对它按位取反再加1。比如3的二进制是00000011按位取反得11111100再加1得11111101这就是-3的补码。验证一下3 (-3) 00000011 11111101 100000000超过8位丢掉进位剩00000000完美归零。为什么能这样你可以拿钟表打比方。钟表是12进制13点和1点其实是同一个位置对8位二进制来说模是256所以-3和253在“取余”的意义上是同一个数减去3和加上253效果相同而253恰好就是11111101补码对应的无符号整数值。这就是补码把减法统一成加法的底层逻辑。正因为这个设计8位有符号数的负数是-128而不是-127因为0只有一种编码00000000而10000000就空出来留给-128了。3.3 移位运算乘除法的底层真相书中还讲了一个非常实用的话题移位运算。虽然现在的CPU有乘法器直接用乘法指令就行但理解移位对理解底层性能优化和位运算代码很有帮助。规则很简单无符号数左移1位相当于乘以2右移1位相当于除以2。比如5的二进制0101左移1位得到1010也就是10右移1位得到0010也就是2多余的一位被丢掉相当于向下取整。这个规律的本质是“位置计数法”的必然结果二进制每向左挪一位权值就放大2倍。在早期没有乘法指令的CPU上编译器会把“乘以2”优化成“左移1位”把“乘以10”优化成“左移3位加左移1位”因为移位比乘法快得多。即使今天你在优化性能敏感代码时看到a 2、b 1这种写法也能立刻反应过来它想干什么。需要留意的是右移分逻辑右移和算术右移。逻辑右移高位一律补0算术右移则保留符号位。对有符号负数来说算术右移能保持符号不变这一点如果搞错很可能会出现“除2之后变成很大的正数”的诡异bug。3.4 逻辑运算程序里的位级开关第2章最后一般会落到逻辑运算上AND、OR、NOT、XOR。别觉得这是数电课才用的东西日常写代码的位操作全部源于这几个运算。三个最实用的结论AND按位与可以用来“提取”或“清零”某些位。想保留一个数低4位、把高4位清掉就与0x0F做按位与。OR按位或用来“置位”把某一位强行设为1。权限管理里给用户加一个读权限就用OR。XOR按位异或相同为0、不同为1可以用来“翻转”特定位也是很多简易加密算法的核心。这套东西在底层协议解析里无处不在。比如一个8位的状态寄存器第0位表示设备在线第1位表示有数据待读第2位表示错误标志你就可以用(status 0x01)判断在线用(status 0x04)判断错误而不用把整个状态字段拆成三个变量。一次读一个字节三个判断效率极高。4. 学完这一章能干点啥4.1 手写一个进制转换工具光看书不做题等于白看。我建议你动手写一个进制转换小工具不用调现成函数从零实现才能把“位权”刻进脑子里。下面是我常用的最小Python实现可直接运行def dec_to_bin(n): if n 0: return 0 bits [] while n 0: bits.append(str(n % 2)) n // 2 return .join(reversed(bits)) def bin_to_dec(bits): val 0 for ch in bits: val val * 2 int(ch) return val print(dec_to_bin(37)) # 输出 100101 print(bin_to_dec(100101)) # 输出 37这段代码不依赖任何黑魔法。核心就是反复取余数再反向拼接反过来就是迭代乘2累加。理解了这两个函数的循环过程你对“逢二进一”的理解就彻底落地了。建议你在纸上也走一遍来验证37除以2余1、商1818除以2余0、商9以此类推最后把余数逆序排就是100101。4.2 实战一位运算做权限管理二进制在业务代码里最常见的应用就是用一个整型变量去管理多个开关状态。比如一个后台系统的文件权限要标记“可读、可写、可执行”你当然可以定义三个bool变量但更优雅的做法是分配三个位。READ 0b100 # 4 WRITE 0b010 # 2 EXEC 0b001 # 1 # 初始状态没有任何权限 perm 0b000 # 添加权限 perm | READ perm | WRITE # 判断权限 if perm READ: print(可读) if perm WRITE: print(可写) if perm EXEC: print(可执行) # 移除写权限 perm ~WRITE这里的|、、 ~看起来有点抽象但你把整型当成一串灯泡开关就懂了置1是开灯、清0是关灯、判断是看灯是否亮着。Linux系统里你天天见的chmod 755其实就是三位八进制数拆成二进制位7 111表示读、写、执行全开5 101表示读、执行开写关。用二进制视角再看权限一切清清楚楚。4.3 实战二IP地址与子网掩码的二进制视角网络协议同样逃不开二进制。IP地址192.168.1.10看起来是四段十进制路由器和操作系统的眼里它就是32位二进制分成4组192.168.1.10 11000000.10101000.00000001.00001010 255.255.255.0 11111111.11111111.11111111.00000000子网掩码的作用就是通过按位与运算把IP地址中“网络号”部分保留下来把“主机号”部分清零。192.168.1.10跟255.255.255.0做AND结果就是192.168.1.0这就是它所属的网络段。不理解二进制就理解不了“为什么子网掩码必须是连续的1”也理解不了“为什么CIDR写法/24等价于255.255.255.0”。凡是网络排查中碰到这种基础的最后追溯到底层都是二进制。5. 常见误区和避坑经验5.1 溢出回绕255加1为什么会变成0我在实际项目中踩过最典型的一次坑就是时间戳字段用了8位无符号整型。设备上报的序列号每隔一段时间就跳到0一开始还以为是通信问题抓包半天没查出毛病最后才发现是数据在内存里回绕了255再加18位位模式从11111111变成00000000于是归零。这类问题的排查思路可以整理成一张速查表现象二进制层面的原因处理建议计数到最大值后归零无符号整型溢出回绕换成更大类型或检查临界值正数加正数变成负数有符号整型溢出留意中间运算结果是否超范围负数存进去读出来变成大正数符号位被当作数值位保证读写双方类型一致移位之后结果异常算术右移与逻辑右移混淆明确是有符号还是无符号数请永远记住程序里没有“数学上的无限”任何数据都有二进制位数限制超出的高位会被无情丢弃。写代码时多问一句“这个值最大能到多少”能省下大量排查时间。5.2 用xxd看文件的二进制真面目学完这一章我强烈建议你亲眼看看文件在二进制层面的样子。在Linux或macOS终端下随便写个文本文件echo abc test.txt xxd test.txt你会看到类似这样的输出00000000: 6162 630a abc.61、62、63分别是a、b、c的ASCII十六进制码0a是换行符。你平时用文本编辑器看到的“字符”在文件里就是这些字节序列。再用file命令或者直接看可执行文件的头部例如编译一个C程序然后执行xxd a.out | head会发现文件头部出现7f 45 4c 46也就是ELF魔数。所有文件——文本、图片、压缩包、可执行程序——本质上都是字节流只是格式约定不同。这个认知能让你在看“文件无法识别”“文件头损坏”这类报错时直接动手从二进制层面找原因。5.3 乱码的二进制根源乱码是每个开发者都遇到过的。理解了二进制乱码就不再神秘。乱码的根源是同一个字节序列被不同的字符编码规则解释了。一个中文字符在GBK编码下占2字节在UTF-8编码下占3字节。以“程”字为例GBKB3 CC两个字节UTF-8E7 A8 8B三个字节如果一段文本原本是UTF-8编码你用GBK解码字节流就会被拆成错误的分组猜出完全不同的字符屏幕上自然是一堆“锟斤拷”“烫烫烫”之类的乱码。解决方式也很粗暴确认文件的真实编码然后用对应编码打开。Windows记事本老版本默认ANSILinux默认UTF-8跨平台传文件最容易踩这个坑。除此之外我还想提醒一句在日志、数据库、接口传输里尽量统一字符编码。我的做法是全世界一律UTF-8没得商量。这个习惯救过我无数次。最后分享一段实际经历。前两年排查一起设备上报数据错乱问题整个团队查了整整一天最后发现就是“数据回绕”四个字一个计数器字段被定义成单字节无符号类型溢出归零后后续所有逻辑全部错位。那一刻我真切感受到第2章里那些干巴巴的二进制知识不是考试用的是拿来救命的。你现在觉得二进制绕是因为还没把它跟具体问题挂上钩。多动手写几个转换工具、多看几次文件的hexdump、多思考几个位运算场景用起来之后就再也丢不掉了。这本书的逻辑也恰恰是先把“数据到底怎么存”的地基打好后面讲内存、讲文件、讲网络你才会有真正“跑起来了”的感觉。

相关新闻

Python装饰器从入门到精通:原理、实战与避坑指南

Python装饰器从入门到精通:原理、实战与避坑指南

有一段时间我负责一个内部数据平台,某天用户报了个bug:同一个报表任务被重复执行了两次。我沿着调用链查了半天,最后发现问题压根不在业务逻辑里,而是出在一个装饰器上——当时图省事给某个函数加了日志,但日志器上被重…

2026/10/5 4:46:39 阅读更多 →
DeepSeek Harness桌面端实战:API Key配置、插件管理与离线部署避坑指南

DeepSeek Harness桌面端实战:API Key配置、插件管理与离线部署避坑指南

1. 从命令行到桌面窗口:DSH 到底解决了谁的痛点DeepSeek Harness 这个项目在圈子里其实已经不算新面孔了,但很长一段时间里,它的使用门槛都卡在“你得先会折腾命令行”这一步。官方桌面端出来之后,情况变了——不用再对着终端敲一…

2026/10/5 4:46:39 阅读更多 →
不用大模型也能做虚假新闻检测:MLP加TF-IDF全流程实战

不用大模型也能做虚假新闻检测:MLP加TF-IDF全流程实战

简介:基于Python和MLP实现的互联网虚假新闻检测器,是一个涵盖数据预处理、模型训练、参数调优与预测输出的完整机器学习项目,主要面向自然语言处理初学者、计算机专业学生及需快速搭建文本分类模型的开发者,适用于课程设计、毕业设…

2026/10/5 4:46:39 阅读更多 →

最新新闻

IT6801显示控制器驱动开发:Datasheet、寄存器与移植实战

IT6801显示控制器驱动开发:Datasheet、寄存器与移植实战

简介:面向ITE6801/IT6801显示控制器的全套资料,主要服务嵌入式显示驱动开发工程师与C/C底层编程人员,重点解决屏幕初始化、寄存器配置、时序调试与驱动移植问题。压缩包共15个文件、约10.37MB,主体为9份PDF数据手册和编程指南&…

2026/10/5 5:20:52 阅读更多 →
Java工程师转型AI Agent实战:从LangChain4j到生产级并发与RAG落地

Java工程师转型AI Agent实战:从LangChain4j到生产级并发与RAG落地

1. Java 工程师转型 AI Agent 的底层逻辑与路径选择1.1 为什么 Java 工程师转 AI Agent 有天然优势很多 Java 工程师一提到 AI Agent,第一反应是“这是 Python 的天下,我是不是得从头学一门语言”。我刚开始接触这个方向时也有同样的焦虑,但实…

2026/10/5 5:20:52 阅读更多 →
二维数组子数组筛选全解析:C#与C语言实现及边界避坑

二维数组子数组筛选全解析:C#与C语言实现及边界避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 5:20:52 阅读更多 →
一张图加一段音频生成数字人:从原理到实操的完整指南

一张图加一段音频生成数字人:从原理到实操的完整指南

数字人这个方向我前前后后折腾了快两年,从最早用现成SaaS工具套模板,到后来自己搭管线跑模型,踩过的坑能写满一个笔记本。最近半年,圈子里讨论最多的就是“一张图加一段音频直接出片”的方案——不需要3D建模,不需要动…

2026/10/5 5:20:51 阅读更多 →
单文件HTML跨年祝福页制作指南:倒计时、烟花与部署

单文件HTML跨年祝福页制作指南:倒计时、烟花与部署

简介:HTML跨年主题网页源码包,面向网页设计与前端初学者,可用于制作春节、跨年庆祝页面。包内包含完整的前端文件,涵盖烟花特效、新年倒计时、祝福弹窗、背景音乐切换及响应式布局等常见节日页面功能,适合直接运行查看…

2026/10/5 5:20:51 阅读更多 →
航班飞行网图分析实战:基于Spark GraphX的图计算应用

航班飞行网图分析实战:基于Spark GraphX的图计算应用

做航班数据分析这几年,我越来越觉得把航班数据当普通关系表来算,其实有点浪费。航线的本质就是一张巨大的图——机场是顶点,航班是边,旅客中转天然就是在图上做路径遍历。刚接触 Spark 的时候我也习惯性用 DataFrame 做 join 和 g…

2026/10/5 5:19:51 阅读更多 →

日新闻

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:22 阅读更多 →
AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

1. 从“plugins”这个词说起:它到底在解决什么问题如果你最近在折腾 AI 编程工具,尤其是 Cursor、Codex CLI、Claude Code 这类带 CLI 的编辑器或命令行助手,那你大概率绕不开一个词——plugins。这个词本身不新鲜,从浏览器到 IDE…

2026/10/5 0:00:23 阅读更多 →
第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:23 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 5:06:42 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 1:10:22 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 3:06:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:14:29 阅读更多 →