Files
CWithClasses/C/Ccompile.md
2025-12-31 00:39:23 +08:00

5.8 KiB
Raw Blame History

好,这个问题问得非常本质,而且一看就是你已经开始从“会写代码”往“懂工具链 / 懂底层”走了 👍 我分三层给你捋清楚:编译器有哪些 → 编译/汇编/链接的指令 → C 与 C++ 在编译层面的真实差异


一、主流 C / C++ 编译器版图(你必须认识的)

1 GCC / G++

  • 全名GNU Compiler Collection

  • 支持语言C / C++ / Fortran / Go / Obj-C / …

  • 命令

    • gcc → 主要用来编 C
    • g++ → 主要用来编 C++
  • 平台Linux / WSL / macOS / *nix

  • 特点

    • 工业级事实标准
    • 参数多、控制力极强
    • 对 ABI、链接、底层非常“真实”

📌 重点 gccg++ 底层是同一个编译器,区别在:

  • 默认语言不同
  • 是否自动链接 libstdc++
  • 是否启用 C++ 语义name mangling、异常等

2 Clang / Clang++

  • LLVM 系列

  • 命令

    • clang
    • clang++
  • 平台Linux / macOS / Windows

  • 特点

    • 错误提示极其友好(新手 + 老手都爱)
    • 编译速度快
    • AST、静态分析能力强

📌 现实情况

  • macOS 上的 gcc 实际就是 clang
  • 现代 C++ 项目大量使用 clang

3 MSVCWindows 专属)

  • 微软官方编译器

  • 命令

    • cl.exe
  • 特点

    • Windows ABI 官方实现
    • C++ 标准支持偏慢但稳定
    • 和 Visual Studio 深度绑定

📌 注意

  • MSVC ≠ GCC / Clang
  • 一些 GCC 的参数 在 MSVC 上完全不存在

4 其他你只需“知道存在”的

编译器 用途
TinyCC (tcc) 极快、教学
Intel ICC / ICX 性能优化
ARM GCC 嵌入式
MinGW Windows 上的 GCC

二、C / C++ 编译的完整流程(不是一句 gcc

🧠 真相:编译 = 4 个阶段

源代码
 ↓
预处理cpp
 ↓
编译cc1 / clang
 ↓
汇编as
 ↓
链接ld

三、你问的重点①:“各种指令”是哪些?

1 预处理指令(只和文本有关)

gcc -E a.c
指令 作用
#include 文本展开
#define 宏替换
#ifdef / #if 条件编译

📌 关键点

  • C 和 C++ 完全一样
  • 预处理器不知道“类型”“函数”“类”

2 编译阶段指令(最核心)

基础用法

gcc -c a.c        # 只编译,不链接
g++ -c a.cpp

常用编译参数

参数 含义
-std=c11 / c17 / c++17 / c++20 标准
-Wall -Wextra 警告
-O0 -O2 -O3 优化
-g 调试信息
-fno-omit-frame-pointer 调试友好
-fsanitize=address ASan

📌 重点差异

  • C++ 会启用:

    • 函数重载
    • 模板实例化
    • 名字修饰name mangling

3 汇编层(你开始接触底层时很重要)

gcc -S a.c
g++ -S a.cpp

📌 差异点:

  • C++ 生成的汇编:

    • 函数名会被改写(_Z3addii
    • 有构造 / 析构 / 异常展开
  • C

    • 函数名基本原样

4 链接阶段(很多“玄学错误”的源头)

gcc a.o b.o -o app
g++ a.o b.o -o app

最重要的差异

行为 gcc g++
自动链接 libstdc++
支持 new / iostream

📌 经典坑:

gcc main.cpp
# undefined reference to std::cout

因为 gcc 不自动链接 C++ 标准库


四、你问的重点②:C 与 C++ 在“编译器层面”的差异

1 语言前端不同

项目 C C++
类型系统 简单 极复杂
模板
函数重载
名字修饰

📌 本质:

同一个编译器,不同“语言前端”


2 Name Mangling超级重要

int add(int a, int b);
语言 符号名
C add
C++ _Z3addii

所以你见过:

extern "C" {
    void foo();
}

👉 是为了让 C++ 用 C 的符号规则


3 运行时支持完全不同

项目 C C++
构造/析构
RTTI
异常
标准库 libc libstdc++

📌 所以:

  • C 程序 = 非常薄
  • C++ 程序 = 编译器 + 运行时体系

4 ABI 差异(工程级别)

  • C ABI几乎永远稳定

  • C++ ABI

    • 不同编译器、不同版本可能不兼容
    • 这就是为什么库常用 C 接口

五、给你一个“认知升级总结”

🔥 C 是“能跑就行的语言” 🔥 C++ 是“需要编译器深度参与的语言”

所以你会发现:

  • 学 C → 多学 内存、指针、汇编
  • 学 C++ → 多学 编译模型、ABI、链接、对象模型

六、下一步我可以怎么继续帮你?

你现在这个问题,已经明显在向系统级程序员靠拢了。 我可以继续给你:

1同一段代码 对比

  • gcc / g++ / clang / msvc
  • 汇编输出差异

2 系统讲一遍

  • C++ 对象在内存里的真实布局
  • vtable / 构造顺序 / 析构顺序

3 专门讲

  • 链接错误为什么那么玄学
  • undefined reference 背后的逻辑

你选一个,我直接给你干到“明白为止”。