C++相比C多了什么 语言特性并发内存序与ABI对比

张开发
2026/4/16 13:26:18 15 分钟阅读

分享文章

C++相比C多了什么 语言特性并发内存序与ABI对比
C 相比 C 多了什么语言能力、并发内存序与 ABI 对比“C 比 C 多了什么”表面是语法清单实质是设计哲学差异C强调可移植、贴近硬件的过程式表达C在兼容 C 子集的前提下提供多范式抽象与工程化标准库并逐步形成更完整的并发与类型系统。本文用对照表、示意代码、Mermaid 与 ASCII分层说明语言与类型、标准库与资源管理、并发与内存序、ABI 与工程边界。具体行为以当前CC11/C17/C23与CC11/17/20/23标准及所用编译器为准。目录一句话总览关系鸟瞰C 作为 C 子集示意类型系统与语法对照函数与模块化用户自定义类型struct / class 与 OOP泛型宏、void* 与模板内存与资源malloc、new 与 RAII错误处理返回值、errno 与异常I/O 与字符串标准库与“自带工程设施”现代 C 自 C11 起的主要特性并发与内存序C11 与 C11ABI为什么 C 稳、C 难选型建议附录同功能左右对照节选免责声明一句话总览维度CC设计取向过程式、贴近硬件多范式过程 / OOP / 泛型 / 函数式风格抽象与类型安全相对弱常靠约定与审查更强类型与编译期检查手段更多标准库小而基础 libc 大而全 STL 线程 时间 …资源管理习惯手动为主RAII 智能指针等惯用法并发C11 起有原子与线程标准接口工程上 pthread 仍常见thread/mutex/atomic等与语言惯用法结合紧ABI对外接口常以C ABI为“ lingua franca ”跨编译器/版本/标准库实现时ABI 风险更高关系鸟瞰C 作为 C 子集示意C 子集可写在 .cpp 中过程式 struct 指针C 语言能力概念OOP / 类与虚函数模板与泛型RAII / 构造析构STL 与 iostream命名空间 / 引用 / 重载…┌─────────────────────────────────────┐ │ C 完整语言 │ │ ┌─────────────────────────────┐ │ │ │ 与 C 高度重叠的“C 子集” │ │ │ │ 语法/语义仍可能有细微差异│ │ │ └─────────────────────────────┘ │ └─────────────────────────────────────┘类型系统与语法对照主题CCvoid*与其它指针历史上常可隐式与T*互转C 更严格一般需static_castT*(p)等显式转换boolC99 起有_Bool/stdbool.h的bool原生bool、true、false枚举enum枚举符常泄漏到外层作用域enum class强类型、作用域隔离const有但语义与用法相对朴素更细constexpr、成员const、重载对const敏感等nullptr用NULL常为0表示空指针nullptr类型安全复合字面量C99 有C 规则与版本相关使用上需注意与 C 的差异enum class示意// CColor::RED 不会污染外层名字空间enumclassColor{RED,GREEN};Color cColor::RED;函数与模块化能力CC函数重载无靠不同函数名同名不同参列表默认参数无void f(int x 0);引用无用指针T部分场景语义更清晰内联static inline等inline与 ODR、模板结合更系统命名空间无靠前缀libname_namespace组织大型代码隐式函数声明历史遗留问题老代码C 要求先声明后使用用户自定义类型struct / class 与 OOP点C 的structC 的struct/class成员函数无用函数指针或外部函数模拟可有成员函数、this访问控制无public/protected/privateclass默认private构造 / 析构无构造函数、析构函数继承与多态手写 vtable 模拟virtual、运行时多态classAnimal{public:virtualvoidspeak(){/* ... */}virtual~Animal()default;};classDog:publicAnimal{public:voidspeak()override{/* ... */}};泛型宏、void*与模板手段优点典型问题C 宏无运行时开销无类型、难调试、易污染名字void* sizeof 回调灵活易错、靠人工保证类型一致C 模板类型安全、可编译期求值constexpr编译慢、错误信息冗长templateclassTTmax_of(T a,T b){returnab?a:b;}内存与资源malloc、new与 RAII操作CC分配未初始化内存malloc::operator new不一定等价于new T构造对象手动在malloc内存上“放置”并初始化若模拟 Cnew T分配并调用构造函数释放free不调用析构delete析构 释放异常路径下释放易遗漏RAII析构自动释放// C离开作用域即关闭示意structFile{FILE*fp{};explicitFile(constchar*path):fp(std::fopen(path,rb)){}~File(){if(fp)std::fclose(fp);}};错误处理返回值、errno与异常风格CC返回错误码非常常见仍常见尤其 API 边界errnolibc 错误习惯仍可用异常try/throw/catch无有与 RAII 组合做栈展开清理工程上 C 也常采用Expected / outcome / 错误码风格异常并非“必须用”但是一种语言级机制。I/O 与字符串主题CC格式化 I/Oprintf/scanfstd::cout/std::formatC20等类型安全printf格式串与实参易不一致iostream /format相对更安全字符串char*、strcpy等std::string动态增长与接口标准库与“自带工程设施”C 常见libc 手写数据结构 C 常见libc libstdc/libc/MS STL 算法/容器/线程能力C 常见路径C 常见路径动态数组malloc/realloc 长度字段std::vector关联表手写哈希 / 第三方库std::unordered_map/std::map排序查找qsort/bsearch或手写std::sort/std::binary_search线程与锁pthreadstd::thread/std::mutex时间time.hstd::chrono现代 C 自 C11 起的主要特性特性作用直觉auto减少冗长类型名范围for遍历容器更简洁Lambda就地定义回调右值引用 /std::move资源转移、减少拷贝智能指针显式所有权、减少泄漏constexpr编译期计算与约束ConceptsC20模板约束更可读ModulesC20改善编译边界≠ ABI 银弹并发与内存序C11 与 C11结论先说清C11起stdatomic.h提供_Atomic、atomic_int等类型以及memory_order_*可用atomic_store_explicit/atomic_load_explicit等带内存序的原子操作。C11起std::atomic与std::memory_order在工程资料与标准库封装上更成体系并与线程、锁、条件变量同一套“现代 C”叙事结合。因此差异不仅是“有没有内存序”而是语言 标准库 惯用法的整体体验。C 发布-订阅示例acquire/release#includeatomicstd::atomicintflag{0};intdata0;// 线程 Adata42;flag.store(1,std::memory_order_release);// 线程 Bif(flag.load(std::memory_order_acquire)1){// 典型模式下可依赖与 data 的同步关系具体证明依赖标准内存模型}C11 对应思路explicit 内存序#includestdatomic.hatomic_int flag;intdata;/* 线程 A */data42;atomic_store_explicit(flag,1,memory_order_release);/* 线程 B */if(atomic_load_explicit(flag,memory_order_acquire)1){/* ... */}常见memory_order对照C 命名C11 枚举同名思想内存序直觉relaxed只关心原子性几乎不管顺序acquire/release成对建立“先发生于”关系acq_rel读改写一条指令上的组合seq_cst全局顺序一致最保守线程 B共享内存线程 A线程 B共享内存线程 A写 datarelease 写 flagacquire 读 flag读 data与同步配对时可见ABI为什么 C 稳、C 难ABI 决定二进制能否对接调用约定、符号修饰、对象布局、异常传播、标准库内部结构等。C为什么常成为“跨边界标准”原因说明对象模型简单无类布局、vtable符号名简单一般接近源函数名生态惯性OS、动态库、FFI 长期以C ABI暴露C高风险点风险后果Name mangling同名重载经修饰后符号不同编译器间规则不同类布局 / vtable继承、虚函数、对齐填充导致布局差异异常与 RTTI运行时实现相关标准库实现libstdc / libc / MS STL 内部对象布局不同C 调用 add ----符号表---- add C 调用 foo(int) / foo(double) ----mangling---- _Z3fooi / _Z3food 示意非唯一规则工程实践对外 C ABI对内 CexternCintapi_add(inta,intb);// 以 C 链接导出便于跨语言/跨编译器边界选型建议场景倾向操作系统内核、极小编译单元、ABI 极敏感边界C或C ABI大型应用、复杂领域模型、强依赖 STL 与抽象C跨语言 SDKC ABI C 实现最常见附录同功能左右对照节选以下片段用于并排体会同一意图在 C 与 C 中的写法差异C 侧重显式状态与资源路径C 侧重封装与标准库。为可读性省略部分头文件与极端错误分支C 侧线程示例以 POSIXpthread示意Windows 原生开发常改用 Win32 线程或其它库思路相同。C 风格vector 封装 realloc 策略RAII 流对象lock_guard mutexC 风格手工长度/capacityfopen/fclose 分支pthread_mutex_lock1. 动态数组末尾追加元素侧要点C自管data / size / capacityrealloc失败要回滚或报错Cvector内聚策略与异常/强保证依实现与操作而定C示意#includestdlib.hstaticintpush_int(int**data,size_t*len,size_t*cap,intx){if(*len*cap){size_tncap*cap?*cap*2u:4u;int*nd(int*)realloc(*data,ncap*sizeof(int));if(!nd)return-1;*datand;*capncap;}(*data)[(*len)]x;return0;}/* 使用int *aNULL; size_t n0,cap0; push_int(a,n,cap,42); … free(a); */C示意#includevectorstd::vectorinta;a.push_back(42);// 容量增长策略由实现提供2. 读文件并确保关闭侧要点C每条错误路径都要记得fclose常用goto cleanup或层层ifC流对象析构关闭句柄失败用bool/ 异常策略由项目约定C示意#includestdio.hintread_byte_count(constchar*path,long*out_bytes){FILE*fpfopen(path,rb);if(!fp)return-1;if(fseek(fp,0,SEEK_END)!0){fclose(fp);return-2;}longszftell(fp);fclose(fp);if(sz0)return-3;*out_bytessz;return0;}C示意#includefstreamboolread_byte_count(constchar*path,longout_bytes){std::ifstreamin(path,std::ios::binary|std::ios::ate);if(!in)returnfalse;out_bytesstatic_castlong(in.tellg());returntrue;}// 析构关闭文件无需手写 fclose3. 互斥保护共享计数器两线程各加若干次侧要点Cpthread_mutex_*锁配对靠人工勿漏unlockCstd::mutexlock_guard/unique_lock作用域结束自动解锁C pthread示意#includepthread.hstaticpthread_mutex_tg_muPTHREAD_MUTEX_INITIALIZER;staticlongg_count0;staticvoid*worker(void*arg){intn*(int*)arg;for(inti0;in;i){pthread_mutex_lock(g_mu);g_count;pthread_mutex_unlock(g_mu);}returnNULL;}/* main创建两个线程 join此处略 */C示意#includemutex#includethreadstd::mutex g_mu;longg_count0;voidworker(intn){for(inti0;in;i){std::lock_guardstd::mutexlock(g_mu);g_count;}}/* mainstd::thread t1(worker, n), t2(worker, n); t1.join(); t2.join(); */附录小结表任务C 常见负担C 常见收益动态数组realloc、容量策略、错误码vector统一接口文件句柄多出口路径下配对关闭RAII 自动释放锁显式 lock/unlock作用域守卫类免责声明本文为技术对比与学习整理。C 与 C 兼容细节例如const、链接、inline、VLA 等随标准版本变化ABI与优化级别强相关。生产结论请以目标工具链文档与实测为准。主题C、C、类型系统、模板、RAII、并发、内存序、ABI。

更多文章