ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

OI-wiki 语言对比指南:C++ 与 C、Python、Java 的核心差异详解

2026/9/12 17:25:08 拓冰建站 浏览量
OI-wiki 语言对比指南:C++ 与 C、Python、Java 的核心差异详解 OI-wiki 语言对比指南C 与 C、Python、Java 的核心差异详解【免费下载链接】OI-wiki:star2: Wiki of OI / ICPC for everyone. 某大型游戏线上攻略内含炫酷算术魔法项目地址: https://gitcode.com/GitHub_Trending/oi/OI-wiki导读本文以 OI-wiki 语言教程中的 C 与其他常用语言的区别 为主体系统梳理 C 与 C、Python、Java 三种语言在语法、类型系统、内存管理与运行机制上的关键差异。C 几乎是 C 的超集C/C 代码混用一般也没有问题但两者之间仍存在一些重要且容易被忽略的区别——不了解这些区别在混写代码时容易碰到奇怪的 bug。如果你是以 C 为主力语言的 OIer本文能帮你更顺利地上手 C如果你同时接触 Python 或 Java也能通过对比更深刻地理解 C 的设计取舍。读完本文你将掌握 C/C 混编时的常见陷阱、C 独有特性模板、引用、constexpr、new/delete的适用场景以及 Python、Java 与 C 在抽象层次上的本质差别。C 相比 C 增加的独特特性可以进一步阅读 OI-wiki 中的 C 进阶教程 部分。C 与 C 的区别宏与模板C 语言中宏#define通过预处理期的纯文字替换来模拟泛型或常量替换过程发生在编译器进行语法与类型检查之前因此宏错误往往难以定位且容易引发副作用如多次求值。C 的模板template在设计之初的一个用途就是用来替换宏定义。学会模板编程是从 C 迈向 C 的重要一步。与宏的文字替换不同模板在编译期实例化会得到更全面的编译器检查便于编写更健全的代码。模板特性在 C11 后支持了可变长度的模板参数表variadic templates可以用来替代 C 中的可变长度函数如printf风格的va_list并保证类型安全——每个参数在编译期都有确定的类型不再依赖调用方与实现方对参数类型的约定。从 OI-wiki 的 常量与 constexpr 页面可以看到constexpr正是“用编译期机制替代宏”的另一个典型constexpr修饰的变量强制要求编译器在编译时计算结果可用来替换宏定义的常量规避 宏定义的风险。算法题中常用constexpr存储数据规模较小的变量以消除运行时计算开销尤其是在 打表 技巧中使用constexpr修饰的数组等容器存储答案。指针与引用C 中你仍然可以使用 C 风格的指针但是对于变量传递而言更推荐使用 C 的引用reference特性来实现类似的功能。引用可以看成是 C 封装的非空指针它在声明时必须指向对象且指向的对象不能为空因此可以避免一些空地址访问的问题。不过指针由于其灵活性可以重新指向、可以为空、可以参与指针运算也仍然有其用武之地。关于NULL与nullptrC 中的NULL空指针在 C11 起有了类型安全的替代品nullptr。如 指针 页面所讲C11 之前 C 与 C 一样使用NULL宏表示空指针常量NULL与整数0的混用会导致重载决议出错——例如存在int f(int)与int f(int*)两个重载时调用f(NULL)实际匹配的是int(int)而不是int(int*)。nullptr的类型为std::nullptr_t空指针类型它可以隐式转换为任何指针类型转换结果是该类型的空指针值从而避免了整型与指针混淆的问题。引用和指针之间可以通过*和运算符相互转换相关运算符的详细用法可参考 运算符 页面中的“成员访问运算符”一节。引用更完整的语义左值引用、右值引用、悬垂引用等参见 引用。OI 实用提示在 引用相关的优化技巧 中特别指出——对非轻量对象如std::vector、std::string、std::map等容器入参使用引用可以消除拷贝开销但对轻量对象基本类型int、float较小的聚合体类型标准库容器的迭代器使用引用反而没有任何好处引用类型作为参数的空间占用可能比类型本身还大并可能阻止编译器优化。bool另请参阅 OI-wiki 的 布尔类型 一节。与 C 不同的是C 语言最初并没有布尔类型。C99 标准加入了_Bool关键字以及等效的bool宏以及true和false两个宏。如果需要使用bool、true、false这三个宏需要在程序中引入stdbool.h头文件而使用_Bool则不需要引入任何额外头文件。stdbool.h中的宏定义形如#define bool _Bool #define true 1 #define false 0C23 起true、false和bool成为 C 语言中的关键字使用它们不需要再引入stdbool.h头文件同时保留_Bool作为bool的替代拼写形式。C23 还规定 C 语言的bool类型不再使用整型的零与非零值定义而是定义为足够储存true和false两个常量的类型并且可以通过limits.h中的宏常量BOOL_WIDTH获取布尔类型的位宽。下表展示了 C 语言不同标准下 bool 类型支持的变化情况作为对照加入了 C 的支持情况语言标准booltrue/false_BoolC89//保留C99 起C23 以前宏与_Bool等价需要stdbool.h头文件宏true与1等价false与0等价需要stdbool.h头文件关键字C23 起关键字关键字关键字bool的替代拼写形式C关键字关键字保留注C 和 C 均规定以一个下划线跟着一个大写字母开头的标识符是被保留的因此上表中_Bool在 C89 及 C 中被标记为“保留”而不应被用户使用。补充背景C 中bool是内建关键字取值只可能是true和false一般情况下占用 1 字节空间由于历史原因C 中布尔类型会被视作特殊的整型bool到int的转换属于数值提升false变为0true变为1详见 类型转换。struct尽管在 C 和 C 中都有 struct 的概念但它们对应的东西是不能混用的这是写 C/C 混合代码时尤其致命的一点C 中的 struct 用来描述一种固定的内存组织结构——它是一组成员的内存布局描述没有成员函数、没有访问控制。C 中的 struct就是一种类与class唯一的区别就是它的成员和继承行为默认是 public 的而一般类class关键字定义的默认成员是 private 的。这一点在写 C/C 混合代码时尤其致命同一个结构体声明在两套语义下可能表现出完全不同的行为。正如 OI-wiki 的 结构体 页面所说明的本页描述的struct不同于 C 中struct在 C 中struct被扩展为类似 类 的类说明符类 页面也明确指出“struct关键字定义的也是类”C 因为历史原因保留并拓展了struct。访问说明符public、protected、private的默认值差异如下struct所有成员默认publicclass所有成员默认private。另外声明 struct 时 C 也不需要像 C 那么繁琐。C 版本需要在struct类型名之外再用typedef定义别名且成员中引用自身时必须写全struct Node_t *nexttypedef struct Node_t { struct Node_t *next; int key; } Node;C 版本中struct本身就是类型名可以直接使用成员声明也无需struct前缀struct Node { Node *next; int key; };constconst 在 C 中只有限定变量不能修改的功能而在 C 中由于大量新特性的出现const 被赋予了更多的用法C 中的 const 在 C 中的“继任者”是constexpr。constexprC11 起要求编译器能在编译时求得函数或变量的值实现编译期计算与硬编码优化。C 中的 const 的完整用法常量、常量引用/常量指针、const 成员函数等请参见 OI-wiki 的 常值 页面。两者最直观的区别可以理解为const是「只读」constexpr是「不可变」。例如下面的代码constexpr int a 10; // 直接定义常量 constexpr int FivePlus(int x) { return 5 x; } void test(const int x) { std::arrayint, x c1; // 错误x 在编译时不可知 std::arrayint, FivePlus(6) c2; // 可行FivePlus 编译时可知 }OI-wiki 的 常值 页面还给出了一个用constexpr实现编译期斐波那契计算的例子constexpr修饰的fib0函数在唯一的调用处使用了常量参数整个函数仅在编译期运行编译器不需要为其生成运行时汇编代码输出v0时直接用最终计算结果替代而普通fib1函数仍保留运行时递归调用。同时需注意编译时计算量过大会导致编译错误如constexpr递归深度超过限制Clang 会报constexpr evaluation exceeded maximum depth此时应考虑改用const。内存分配C 中新增了new和delete关键字用来在自由存储区free store上分配空间。这个自由存储区可以是堆也可以是静态存储区它们是为了配合「类」而出现的new会调用类型的构造函数delete会调用类型的析构函数delete[]能够直接释放动态分配的数组内存非常方便相比 C 中的malloc()、realloc()、free()函数new/delete对类型有更完善的支持类型安全、构造/析构语义但是效率不如C 中的这些函数后者不做构造与析构只是一块裸内存的分配与回收。实践建议可以概括为如果你需要动态分配内存的对象是基础类型或它们的数组可以使用malloc()进行更高效的内存分配如果你新建的对象是非基础类型类对象、需要构造/析构的类型建议使用new以获得类型安全检查与构造/析构语义。一个必须牢记的混用红线尽管new和malloc()都返回指针但new出来的指针只能用delete回收而malloc()出来的指针也只能用free()回收。交叉使用如new后free或malloc后delete会带来内存泄漏甚至未定义行为的风险。变量声明C99 前C 语言的变量声明必须位于语句块的开头所有声明先于语句这也是 C89 风格的代码中常见把int i;等声明集中在块首的原因。C 和 C99 之后则无此限制变量可以在首次使用的位置就近声明。就近声明在 OI 中非常实用例如在for (int i 0; ...)的循环初始化语句中声明循环变量作用域被限制在循环内避免污染外层命名空间。可变长数组C99 后C 语言支持 VLAVariable-Length Array可变长数组即数组长度可以在运行时才确定int n; scanf(%d, n); int a[n]; // C99 起合法VLAC 始终不支持 VLA。在 C 中数组长度必须是编译期常量需要运行时确定大小的场景应使用std::vector或在 C 中通过new int[n]动态分配。这也是 C 代码在移植到 C 时常见的编译报错来源之一。结构体初始化C99 后C 语言支持结构体的指派符初始化designated initializer例如{.key 1}不过在 C11 中该特性为可选特性。C 直到 C20才支持有顺序要求的指派符初始化按成员声明顺序且能力比 C 更受限——C 语言支持的以下特性 C 都不支持乱序指派成员顺序与声明顺序不一致嵌套指派与普通初始化器混用数组的指派符初始化。这意味着把 C 代码里的指派符初始化直接搬进 C尤其 C17 及更早可能无法通过编译混编时需要改写为顺序初始化或使用聚合初始化。注释语法C 风格的单行注释//C 语言于C99 前不支持C89 只支持/* ... */块注释。也就是说在严格 C89 模式下编译 C 代码时遇到//会报错C99 起//被纳入标准。Python 与 C 的区别Python 是目前机器学习界最常用的语言。相比于 CPython 的优势在于易于学习易于实践Python 有着更加简单直接的语法比如定义变量时不需要提前声明变量类型动态类型类型在运行时确定语法简洁、生态丰富适合快速原型开发。但是这样的简单也是有代价的——Python 相比于 C 牺牲了性能C 几乎适用于包括嵌入式系统的所有平台并且有着更快的执行速度编译为本地机器码Python 只可以在某些支持高级语言解释器/运行时的平台上使用且动态类型、解释执行与垃圾回收带来明显的运行时开销C 更接近底层所以可以用来进行编写操作系统直接操作内存、寄存器、系统调用等。对 OI 场景而言C 的高性能与底层控制能力正是它在算法竞赛中成为主力语言的原因参见 语言教程索引在 OI 中最常用的编程语言是 C。Java 与 C 的区别Java 与 C 都是面向对象的语言都使用了面向对象的思想封装、继承、多态。由于面向对象有许多非常好的特性继承、组合等因此二者有很好的可重用性。所以相比于 PythonJava 和 C 更加类似——语法风格接近类型都是静态的都强调 OOP 设计。二者最大的区别在于Java 有 JVM 的机制JVM 全称是Java Virtual Machine中文意为Java 虚拟机Java 语言的一个非常重要的特点就是与平台的无关性而使用 Java 虚拟机是实现这一特点的关键一般的高级语言如果要在不同的平台上运行至少需要编译成不同的目标代码而引入 Java 语言虚拟机后Java 语言在不同平台上运行时不需要重新编译Java 语言使用 Java 虚拟机屏蔽了与具体平台相关的信息使得 Java 语言编译程序只需生成在 Java 虚拟机上运行的目标代码字节码bytecode就可以在多种平台上不加修改地运行。因为这个特点Java 经常被用于需要移植到不同平台程序的开发如跨平台的企业级应用、Android 应用等。但另一方面由于编译 Java 程序后运行时还需要从字节码开始由 JVM 解释/即时编译执行JIT所以Java 的性能没有 C 好——这也是 OI 与高性能计算领域更青睐 C 的原因之一。总结三种语言对比速览维度CCPythonJava类型系统静态类型静态类型支持模板泛型动态类型静态类型执行方式编译为机器码编译为机器码解释执行编译为字节码JVM 运行内存管理手动malloc/free手动new/deleteRAII自动垃圾回收自动垃圾回收平台无关性需为各平台分别编译需为各平台分别编译需平台有解释器一次编译处处运行JVM运行性能高高低中低于 C/C典型场景底层开发、嵌入式OI/算法竞赛、系统开发、游戏机器学习、快速原型跨平台企业级应用对于以 OI/ICPC 为目标的读者C 在性能、标准库STL与底层控制力上的综合优势使其成为主力语言而了解 C 语言在 bool、struct、const、内存分配、VLA、指派符初始化等特性上的差异可以有效避免 C/C 混编时的隐蔽 bug。延伸阅读以下 OI-wiki 页面与本文主题直接相关可进一步深入C 进阶类C 中 struct 与 class 的完整语义、访问说明符、成员函数结构体C 中 struct 的使用与内存对齐注意事项引用左值/右值引用、悬垂引用与引用优化技巧指针指针声明、解引用、指针偏移与空指针NULL 与 nullptr常值const 与 constexpr 的完整用法及编译期计算示例布尔类型C/C 布尔类型的历史沿革与类型转换运算符*、、-等与指针/引用相关的运算符语义C11 新特性auto、decltype、范围 for 等现代 C 特性。【免费下载链接】OI-wiki:star2: Wiki of OI / ICPC for everyone. 某大型游戏线上攻略内含炫酷算术魔法项目地址: https://gitcode.com/GitHub_Trending/oi/OI-wiki创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考