为什么 C/C++ 不走 Java 式的虚拟机跨平台路线?
Java 用"统一字节码 + 各平台 JVM"实现了强大的跨平台,C/C++ 明明没有中间虚拟机消耗资源的负担,为什么不去走同样的路?------这个看似简单的问题,其实藏着两种语言哲学、三种历史约束、以及一个关于"跨平台到底是什么"的根本性误区。
目录
- [先破一个误区:C/C++ 到底跨不跨平台?](#先破一个误区:C/C++ 到底跨不跨平台? "#%E5%85%88%E7%A0%B4%E4%B8%80%E4%B8%AA%E8%AF%AF%E5%8C%BAcc-%E5%88%B0%E5%BA%95%E8%B7%A8%E4%B8%8D%E8%B7%A8%E5%B9%B3%E5%8F%B0")
- [两种"跨平台"的本质区别:源码级 vs 二进制级](#两种"跨平台"的本质区别:源码级 vs 二进制级 "#%E4%B8%A4%E7%A7%8D%E8%B7%A8%E5%B9%B3%E5%8F%B0%E7%9A%84%E6%9C%AC%E8%B4%A8%E5%8C%BA%E5%88%AB%E6%BA%90%E7%A0%81%E7%BA%A7-vs-%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%BA%A7")
- [铁律一:C++ 的零开销原则,容不下一个解释器](#铁律一:C++ 的零开销原则,容不下一个解释器 "#%E9%93%81%E5%BE%8B%E4%B8%80c-%E7%9A%84%E9%9B%B6%E5%BC%80%E9%94%80%E5%8E%9F%E5%88%99%E5%AE%B9%E4%B8%8D%E4%B8%8B%E4%B8%80%E4%B8%AA%E8%A7%A3%E9%87%8A%E5%99%A8")
- [铁律二:没有统一 ABI,二进制就无从谈起](#铁律二:没有统一 ABI,二进制就无从谈起 "#%E9%93%81%E5%BE%8B%E4%BA%8C%E6%B2%A1%E6%9C%89%E7%BB%9F%E4%B8%80-abi%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%B0%B1%E6%97%A0%E4%BB%8E%E8%B0%88%E8%B5%B7")
- 铁律三:裸指针与内存模型,在虚拟机里无法安全执行
- 铁律四:系统编程需要直接触摸硬件
- [历史与现实:为什么 C 的跨平台很早就"定死"在源码层](#历史与现实:为什么 C 的跨平台很早就"定死"在源码层 "#%E5%8E%86%E5%8F%B2%E4%B8%8E%E7%8E%B0%E5%AE%9E%E4%B8%BA%E4%BB%80%E4%B9%88-c-%E7%9A%84%E8%B7%A8%E5%B9%B3%E5%8F%B0%E5%BE%88%E6%97%A9%E5%B0%B1%E5%AE%9A%E6%AD%BB%E5%9C%A8%E6%BA%90%E7%A0%81%E5%B1%82")
- [C/C++ 真的没试过字节码吗?------五次失败与一次成功](#C/C++ 真的没试过字节码吗?——五次失败与一次成功 "#cc-%E7%9C%9F%E7%9A%84%E6%B2%A1%E8%AF%95%E8%BF%87%E5%AD%97%E8%8A%82%E7%A0%81%E5%90%97%E4%BA%94%E6%AC%A1%E5%A4%B1%E8%B4%A5%E4%B8%8E%E4%B8%80%E6%AC%A1%E6%88%90%E5%8A%9F")
- 虚拟机不是免费的:把成本算清
- [路线的尽头正在融合:AOT、GraalVM、WASM 与 LLVM](#路线的尽头正在融合:AOT、GraalVM、WASM 与 LLVM "#%E8%B7%AF%E7%BA%BF%E7%9A%84%E5%B0%BD%E5%A4%B4%E6%AD%A3%E5%9C%A8%E8%9E%8D%E5%90%88aotgraalvmwasm-%E4%B8%8E-llvm")
- 总结:目标决定路线,路线决定代价
先破一个误区:C/C++ 到底跨不跨平台?
如果 C/C++ 不跨平台,那么 Windows 上的 Chrome、Linux 上的 MySQL、Mac 上的 Adobe 软件都是怎么来的?
C/C++ 是跨平台 的,而且跨得非常成功。真正的区别在于------它跨的是源码 ,不是二进制:
| Java / Python | C / C++ | |
|---|---|---|
| 跨平台的对象 | 编译产物(字节码) | 源代码 |
| 口号 | Write Once, Run Anywhere(一次编译,到处运行) | Write Once, Compile Anywhere(一次编写,到处编译) |
| 换平台要做什么 | 什么也不做,直接运行 | 重新编译一份针对该平台的原生二进制 |
| 运行时环境 | JVM / 解释器 | 直接运行在操作系统 + CPU 之上 |
所以"为什么 C/C++ 不走跨平台路线"这个问题本身就是一个误区------C/C++ 一直在跨平台,只是把跨平台的适配成本从"运行时"转移到了"编译时"。
真正的、值得追问的问题变成了两个:
- 为什么 C/C++ 坚持源码级跨平台,而不愿像 Java 一样提供二进制级跨平台?
- 为什么 Java 愿意为一个虚拟机付出资源消耗,而 C/C++ 坚决不付?
接下来四个"铁律"回答第一个问题,一个"账单"回答第二个问题。
两种"跨平台"的本质区别:源码级 vs 二进制级
Java 的路线:一次编译,到处运行
scss
.java 源码
│ javac 编译(一次)
▼
.class 字节码 ←──── 跨平台的"二进制"
│
├──→ JVM(Win/Linux/macOS) 各平台一个 JVM
├──→ JVM(Win/Linux/macOS) 各平台一个 JVM
└──→ JVM(Win/Linux/macOS) 各平台一个 JVM
- 字节码是平台无关的中间表示
- 跨平台的工作全部由 JVM 承担(JVM 是平台相关的,但 JVM 你只需装一次)
- 分发的是字节码,用户拿到就能跑
C/C++ 的路线:一次编写,到处编译
bash
.c/.cpp 源码 ←──── 跨平台的"载体"
│
├──→ 编译器A ──→ Windows .exe/.dll
├──→ 编译器B ──→ Linux .so
├──→ 编译器C ──→ macOS .dylib
└──→ 编译器D ──→ 嵌入式 ARM 裸机固件
- 源代码是平台无关的(只要遵守标准、只用跨平台库)
- 每个目标平台需要一个各自的编译器 + 各自的系统头文件 + 各自的平台库 ,产出一份原生机器码
- 分发的是平台相关的机器码,每个平台一份
关键差异:谁承担"适配"?
Java: 适配成本 → 运行时(JVM) → 写一次,处处可用,运行时慢一点
C/C++: 适配成本 → 编译时(编译器+各平台库) → 每个平台编一次,运行时最快
一句话:Java 用"运行时多付资源"买"分发一次";C/C++ 用"每个平台多编译一次"买"运行时不付任何资源"。
现在的问题是:为什么 C/C++ 宁愿选后者?
铁律一:C++ 的零开销原则,容不下一个解释器
零开销原则(Zero-Overhead Principle)
Bjarne Stroustrup 在《The C++ Programming Language》中明确提出 C++ 的基石:
What you don't use, you don't pay for.(你不需要的功能,你不必为它付代价。)
What you do use, you couldn't hand-code any better.(你需要的功能,其实现效率不低于手写汇编。)
把这条原则翻译成对虚拟机的态度:
markdown
C++ 说: 所有代码,都应该编译成原生机器码直接跑。
你(程序员)写的每一行代码,都不该多付哪怕一条指令的解释开销。
Java 说: 所有代码先编译成字节码,运行时由 JVM 解释或 JIT 编译。
我为你提供内存安全、自动回收、跨平台,代价是运行时多花资源。
一次乘法,两种命运
c
// C/C++:编译后直接变成一条 CPU 指令
int x = a * b; // → imul eax, ebx (一条指令,纳秒级)
java
// Java:解释执行时,字节码本身是"真"的乘法,
// 但解释器循环、操作数栈的 push/pop 都有额外开销;
// 即便 JIT 编译成本地码,也无法摆脱 GC 屏障、类型检查等运行时负担
int x = a * b; // → iload_1; iload_2; imul; istore_1
在追求极致性能的场景------游戏引擎(每秒渲染数百万多边形)、高频交易(微秒级延迟)、科学计算(大规模矩阵运算)------解释器的任何一条多余指令都是不可接受的。
关键认知:Java 的 JIT 确实很厉害,但它改变了"代码的等价性"
现代 JVM 的 JIT(Just-In-Time)编译器,峰值性能可以接近甚至追平 C/C++。但要注意:
- 启动慢:JVM 启动 + 类加载 + JIT 预热,一个大应用可能需要几秒到几十秒
- 性能有波峰:JIT 需要"热点检测",运行一段时间后才逐渐优化
- 内存足迹大:JVM 常驻堆、元空间、GC 结构,动辄几百 MB
而 C/C++ 的代码是编译期就优化好的 ------启动即满血,性能稳定可预测。对于实时系统(汽车 ECU、飞机控制系统)、嵌入式设备(内存以 KB 计)、以及一切对"确定性的性能"有要求的场景,运行时的任何不可预测开销都是致命的。
铁律二:没有统一 ABI,二进制就无从谈起
什么是 ABI?
- API(Application Programming Interface):源代码层面的约定。"你怎么调用这个函数"。
- ABI(Application Binary Interface) :二进制层面的约定。"编译后的函数在机器码里长什么样"。
ABI 决定了这些细节:
c
// 同一个 struct,在不同平台/编译器下的内存布局可能完全不同
struct Point {
int x;
int y;
};
// 问题清单:
// 1. int 多大?32 位还是 16 位? → 取决于平台(LP64 vs LLP64)
// 2. x 和 y 之间有没有 padding? → 取决于对齐规则
// 3. 函数参数怎么传?寄存器还是栈? → 取决于调用约定(cdecl/stdcall/...)
// 4. 函数名在机器码里叫什么? → 取决于名称修饰规则
// 5. 空类占几个字节? → C++ 规定最小 1 字节
一个真实的 ABI 灾难
c
// 在 Linux 64 位编译:
sizeof(long) == 8 // LP64
// 在 Windows 64 位编译:
sizeof(long) == 4 // LLP64
同一个 long,同一个源代码,编译出两种大小完全不同的二进制。如果两个平台的二进制文件要通用,这两个平台必须共享同一套 ABI------而 C/C++ 有几十套相互不兼容的 ABI。
Java 是怎么绕开这个问题的?
Java 的根本手段是:在 JVM 内部统一一切。
arduino
Java 源码 → javac → 平台无关的 .class(字节码规范,全球只有一套)
│
▼
各平台 JVM ------ 把字节码翻译成本地机器码
│
▼
这个平台真正跑机器码时,ABI 的差异
由 JVM 自己消化,Java 代码感知不到
- 字节码规范(JVMS)是唯一的标准,由 JVM 规范统一
- JVM 替 Java 代码解决了所有 ABI 差异:整数宽度、结构体对齐、调用约定、内存模型
- Java 代码层面只有一个
int(永远 32 位),不存在 LP64/LLP64 之分
C/C++ 想走二进制跨平台,就得先统一全世界 50 年来积累的 ABI------这是一项不可能完成的任务,因为海量的 .dll/.so/.o 已经按照各自的 ABI 编译、打包、部署了。
一句话:Java 的字节码是一张"全球统一的二进制护照",因为全世界只有一套字节码规范。C/C++ 不可能有这种东西,因为它们的二进制从一开始就是各自为政的。
铁律三:裸指针与内存模型,在虚拟机里无法安全执行
Java 能安全跑在虚拟机里的前提:它没有裸指针
java
// Java:只有引用,没有指针
String s = "hello";
s.length(); // JVM 确保 s 要么非空、要么抛 NPE,绝不会把内存搞坏
- Java 的引用是受控的:JVM 知道每个引用指向哪里,能做空指针检查、类型检查、数组边界检查
- Java 没有指针算术:你不能把引用加 1 然后访问"附近"的内存
- 正因为如此,JVM 才敢做垃圾回收------它需要精确追踪每一个存活对象
C/C++:指针是通向硬件的钥匙,也是安全噩梦
c
// C/C++:指针可以指向内存的任何位置
int* p = (int*)0xDEADBEEF; // 野指针------你可以在任意地址写东西
int arr[4];
int* q = arr + 100; // 越界指针------没有边界检查
*p = 42; // 可能直接写坏内存,甚至写坏虚拟机自己
想象一下:如果 C 代码跑在一个虚拟机上,一个 *(int*)0xDEADBEEF = 42 会直接把虚拟机的内存写坏------虚拟机的安全性在指针面前形同虚设。
更深一层:GC 与指针互斥
垃圾回收器要工作,必须能扫描对象图。它需要知道:
- 哪个内存地址是对象头?哪个是字段?
- 一个字段里的值是"指针"还是"整数"?
c
struct Node {
void* data; // 这是指针还是整数?------GC 无法区分!
int flag; // 这个 int 会不会恰好等于某个地址?
};
C/C++ 允许任何内存位置存放任意值 ,GC 无法可靠地区分"指针"和"数据"。这就是为什么 C/C++ 根本无法享受自动内存管理------没有安全的引用模型,就没有安全的 GC。
一句话:Java 放弃裸指针,换来的是虚拟机的安全边界和垃圾回收。C/C++ 保留裸指针,就等于放弃了"放进安全沙箱"的可能性。这两者是严格互斥的。
铁律四:系统编程需要直接触摸硬件
谁在真正需要"没有中间层"?
| 领域 | 为什么不能有虚拟机 |
|---|---|
| 操作系统内核 | 需要访问 CPU 特权指令、内存分页、中断向量表 |
| 设备驱动 | 需要访问 IO 端口、寄存器映射、DMA |
| 嵌入式 / 单片机 | 内存只有几 KB,根本装不下一个 JVM |
| 实时系统 | 需要硬实时保证,GC 的停顿不可接受 |
| 游戏引擎 | 需要直接调用 GPU 驱动、SIMD 指令、底层内存管理 |
erlang
Linux 内核:97% 由 C 编写
Windows 内核:主体由 C 编写
各种驱动:C/C++
汽车 ECU、飞机飞控:C/C++
游戏引擎(Unity/Unreal):C++
Java 的 JVM 本身就运行在操作系统之上,而操作系统是 C 写的。"让 JVM 去跑一个需要写操作系统的程序"是一个递归矛盾------写操作系统的语言必须先于任何虚拟机存在。
这其实指向一个更深的结论:虚拟机需要建立在"某种东西"之上,而这个基础只能是原生编译的语言。 如果 C/C++ 也依赖虚拟机,那么"承载虚拟机的东西"又得用别的原生语言------总有一层必须是直接跑在硬件上的。
历史与现实:为什么 C 的跨平台很早就"定死"在源码层
C 的诞生:1972 年,为 UNIX 而生
Ken Thompson 和 Dennis Ritchie 设计 C 语言的初衷,是重写 UNIX 操作系统。那时(1970 年代):
- 没有网络,没有跨平台二进制分发的需求
- 计算机架构百花齐放(PDP-11、VAX、IBM 大型机),每个平台都有自己的一套 ABI
- 让 C 在多个平台跑起来的方式,就是每个平台各写一个编译器 + 一份系统头文件
这就是 C 跨平台模型的起源:它不是"设计出来的",而是"长出来的"。 C 标准(ANSI C, 1989)统一的是语言本身 (源码可移植),而操作系统层靠 POSIX 标准 (1988)统一系统调用接口(源码可移植)。
C 的跨平台生态,是一层一层搭出来的:
┌─────────────────────────────────┐
│ 你的 C 源码 │ ← 跨平台(只要只用标准 API)
├─────────────────────────────────┤
│ POSIX / Win32 / ... │ ← 系统调用 API(跨平台的标准)
├─────────────────────────────────┤
│ 各平台的系统库 + 编译器 │ ← 平台相关(编译时消化差异)
├─────────────────────────────────┤
│ Windows / Linux / macOS │ ← 各不相同
└─────────────────────────────────┘
这条路在 2026 年依然高效
有人可能觉得"每个平台重新编译"很落后。但看看现代生态:
bash
# Ubuntu 安装 MySQL:apt 会根据你的系统自动选择正确的二进制包
sudo apt install mysql-server
# macOS 安装 git:Homebrew 自动下载对应架构的预编译包
brew install git
Linux 发行版(apt/yum/dnf)、macOS 的 Homebrew、Windows 的 winget,本质上都是"按平台分发预编译二进制"的自动化工具。 再加上 CI/CD(GitHub Actions 可以同时编译 Windows/Linux/macOS 三个平台的产物),"每平台编译一次"的成本早已被工具链大幅摊薄。
换句话说:C/C++ 不选字节码,不是因为做不到,而是因为它那套"源码 + 平台工具链"的体系,在过去 50 年里已经被打磨得足够好用。
C/C++ 真的没试过字节码吗?------五次失败与一次成功
失败者名录
| 尝试 | 时间 | 结果 |
|---|---|---|
| UNCOL(Universal Computer-Oriented Language) | 1958 | 一个"通用编译器中间语言"的宏大构想,从未真正落地 |
| UCSD p-code(Pascal 字节码) | 1970s | 实验室成功,商业失败------但它启发了 Java |
| C++/CLI(微软,把 C++ 编译到 .NET 的中间语言) | 2005 | 仅限 Windows + .NET 生态,争议巨大,最终被 WinRT 取代 |
| 原生 C 字节码尝试(如 Andes 等) | 各时期 | 均因性能损耗和生态不兼容而失败 |
一次成功:WebAssembly(WASM)
C/C++ 在 2019 年后,真的找到了一条"二进制跨平台"的落地路线------但不在传统平台上:
c
// 把 C 代码编译成 WebAssembly:
// emcc -O3 hello.c -o hello.wasm
int fib(int n) {
return n < 2 ? n : fib(n - 1) + fib(n - 2);
}
markdown
.c 源码 → Emscripten → .wasm 二进制 → 浏览器 / Node.js / 嵌入式 / 边缘设备
↑ 同一个 .wasm,处处运行
WASM 为什么能成,而其他字节码失败?
- 它是一个"受限制的虚拟机":无指针、内存沙箱化、无 GC------恰恰避免了铁律三的问题
- 性能损失可控:WASM 的沙箱设计让 JIT 可以生成接近原生性能的代码
- 生态新:没有 50 年历史包袱,规范可以重新定义
但注意:WASM 的定位是"浏览器/沙箱内的跨平台",不是"系统编程的跨平台"。 你不可能用 WASM 写一个操作系统内核------它恰恰证明了 C/C++ 放弃沙箱安全换来的是"直接跑在硬件上"的能力。
虚拟机不是免费的:把成本算清
问题真正的另一半:Java 凭什么付得起虚拟机的代价?
回到题主的问题:"C/C++ 已经不必担心中间虚拟机带来的资源消耗"------这句话说反了。 更准确的说法是:
Java 不是因为"不用关心虚拟机消耗"才跨平台,而是因为它"愿意承担"虚拟机的消耗,才换来二进制级跨平台。虚拟机不是免费的,Java 只是选择了为跨平台买单。
来算一笔真实的账:
| 维度 | C/C++(原生编译) | Java(JVM) |
|---|---|---|
| 启动时间 | 毫秒级 | 数百毫秒 ~ 数秒(类加载 + JIT 预热) |
| 内存足迹 | 几十 KB ~ 几百 MB | 基础 JVM 就要几百 MB 起 |
| 运行性能(峰值) | 最优 | JIT 后约为原生的 1.0~1.3 倍(个别场景更差) |
| GC 停顿 | 无(手动管理) | 有(虽然现代 GC 已很平滑) |
| 可预测性 | 完全可预测 | 存在不确定性 |
| 需要程序员 | 手动管理内存、手动适配平台 | 内存安全 + 自动跨平台 |
那 Java 到底在买什么?
diff
Java 付出去: Java 买回来:
───────────── ─────────────
- 启动慢 - 一次编译,到处运行
- 内存大 - 内存安全(无野指针、无内存泄漏)
- 有 GC 停顿 - 自动垃圾回收
- 峰值性能略逊 - 动态加载、反射、运行时增强
- 反编译容易 - 庞大的生态与开发效率
一个残酷的现实:Java 反编译 vs C/C++ 反汇编
arduino
Java:.class → 反编译 → 几乎还原成源码(工具:JD-GUI / CFR / 各种破解)
C/C++:.exe → 反汇编 → 恢复成可读逻辑极难(需要逆向工程大师级水平)
商业软件的加密/授权、算法保护、病毒与反病毒对抗------这些领域根本不可能用字节码。这也解释了为什么 C/C++ 至今牢牢占据着游戏、安全、金融核心系统。
路线的尽头正在融合:AOT、GraalVM、WASM 与 LLVM
2026 年的今天,两条"水火不容"的路线正在互相学习、互相靠近。
原生侧在拥抱"统一中间表示":LLVM
LLVM 是 C/C++ 编译器家族的"虚拟机内核"------LLVM IR 就是一个字节码:
bash
.c/.cpp → Clang → LLVM IR(中间表示)→ 各平台后端 → 原生机器码
↑ 这就是"虚拟机的中间层",只是它只存在于编译期
LLVM 的 IR 让"写一种优化,所有平台受益"成为可能------C/C++ 语言家族实际上已经在"编译期的字节码"层面统一了,只是它们拒绝把它带到运行时。
托管侧在拥抱"提前编译":AOT
- Java :GraalVM Native Image 把 Java 字节码提前编译成原生可执行文件------启动毫秒级、内存骤降,代价是牺牲动态加载/反射
- .NET:NativeAOT 让 C# 也能编译成自包含的原生二进制
- Go:从一开始就 AOT 编译,但通过垃圾回收保住了部分内存安全
融合的本质:两者都在回答"中间层放哪"
arduino
中间层放在"编译时" 中间层放在"运行时"
───────────────── ─────────────────
C/C++: ✅ LLVM IR(编译期) ❌ 拒绝
Java: ✅ 字节码(分发物) ✅ JVM(执行)
WASM: ✅ .wasm(分发物) ✅ 沙箱(执行,但受限)
GraalVM: ✅ 字节码(源码层) ❌ 编译期消化,运行时无 JVM
所以 C/C++ 从来不是"拒绝中间层"------它们只是坚持把中间层关在编译器里,不让它在运行时吃资源。
总结:目标决定路线,路线决定代价
回到最初的问题:"C/C++ 明明不必担心中间虚拟机带来的资源消耗,为什么不去像 Java 一样走跨平台路线?"
现在答案已经完整:
第一层:这个问题的前提是错的
C/C++ 一直在跨平台 ,而且跨得极成功------Chrome、MySQL、Linux、Unreal 引擎都是跨平台的成功案例。只是它们的跨平台是源码级 的(一次编写,到处编译),而非 Java 的二进制级(一次编译,到处运行)。
第二层:C/C++ 不选字节码,是四条铁律决定的
| 铁律 | 内容 | 一句话 |
|---|---|---|
| 零开销原则 | 所有代码编译成原生机器码,不为解释付一条多余指令 | 性能是底线,不可交易 |
| 无统一 ABI | 50 年来海量二进制的 ABI 各自为政,无法统一 | 想统一二进制,先统一历史------不可能 |
| 裸指针模型 | 指针可指向任意内存,虚拟机无法安全托管 | 有裸指针,就进不了沙箱 |
| 系统编程需求 | 内核、驱动、嵌入式需要直接触摸硬件 | 总得有一层直接跑在硬件上 |
第三层:Java 的虚拟机不是"免费"的,是"付了钱"的
arduino
C/C++: 省下了运行时开销 → 付的是"每个平台编译一次" + "程序员管理内存"
Java: 省下了平台适配 → 付的是"JVM 常驻内存" + "启动预热" + "GC 停顿"
没有免费的午餐,只有不同的账单。 C/C++ 选择"把成本花在程序员身上"(手动内存、手动适配),Java 选择"把成本花在运行时身上"(JVM 吃资源)。
第四层:两条路线正在靠拢
LLVM IR 让 C/C++ 在编译期尝到了"统一中间层"的甜头;GraalVM、NativeAOT 让 Java/C# 在运行时摆脱了 JVM 的负担;WASM 则是一个"要跨平台、又要沙箱安全、又不心疼一点点性能"的第三条路。
语言是"设计"出来的,更是"取舍"出来的。
C/C++ 不是不懂跨平台,而是更在乎性能;Java 不是不懂性能,而是更在乎跨平台与安全。各取所需,各付各的账------这就是为什么五十年过去,两类语言都在各自的战场上活得很好。
参考资料
- Stroustrup, B. (2013). The C Programming Language (4th ed.). Addison-Wesley. --- 零开销原则、抽象与性能的讨论。
- Ritchie, D. M. (1993). The Development of the C Language. ACM HOPL Conference. --- C 语言起源与 UNIX 的渊源。
- Kernighan, B. W., & Ritchie, D. M. (1978). The C Programming Language. Prentice Hall.
- Gosling, J., Joy, B., Steele, G., et al. (2023). The Java Language Specification, Java SE 21 Edition. Oracle. --- §1.2 Java 的跨平台设计目标。
- Lindholm, T., et al. (2023). The Java Virtual Machine Specification, Java SE 21 Edition. Oracle.
- IEEE Std 1003.1. POSIX.1-2024. --- 系统调用接口的源码级标准化。
- WebAssembly Community Group. WebAssembly Specification. --- webassembly.org/
- LLVM Foundation. The LLVM Compiler Infrastructure. --- llvm.org/
- Oracle. GraalVM Native Image. --- www.graalvm.org/
- Love, R. (2010). Linux Kernel Development (3rd ed.). Addison-Wesley. --- 内核以 C 实现的背景。
发布日期:2026-07-25 · 作者:SemiTris · 预计阅读时间:约 15 分钟