You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

g++中“仅编译”(-S)与“编译并汇编”(-c)选项的区别是什么?

嘿,这个问题问到点子上了——很多刚摸编译流程的同学都会在「编译」和「汇编」这一步搞混,我给你一步步拆解清楚~

先理清整个编译链的顺序

首先回顾下g++的这几个选项对应的完整流程:

  • -E:仅预处理——把#include、#define这些预处理指令展开,生成纯C++代码(没有预处理指令了)
  • -S:仅编译——把预处理后的高级语言(C++)翻译成汇编语言,生成.s后缀的文件
  • -c:编译+汇编——先做-S的步骤,再把汇编语言翻译成机器能识别的机器码,生成.o后缀的目标文件
什么是汇编?

说白了,汇编语言是直接对应CPU指令集的低级语言,是人类能勉强看懂的“机器语言说明书”。每一条汇编指令,几乎都对应CPU能执行的一个基础操作(比如移动数据、加减运算、跳转)。

比如你写一句C++代码:

int sum = a + b;

编译后会生成类似这样的x86_64汇编代码(简化版):

movl    -4(%rbp), %eax   # 把变量a的值加载到eax寄存器
addl    -8(%rbp), %eax   # 把变量b的值加到eax里
movl    %eax, -12(%rbp)  # 把eax里的结果存到sum变量的内存位置

而汇编阶段,就是把这些人类能读的汇编指令,一对一翻译成CPU能直接执行的二进制机器码(比如movl对应一个特定的二进制 opcode),同时处理符号表(比如记录函数名、变量名对应的内存地址占位),最终生成.o目标文件——这个文件是二进制的,直接打开是乱码,但已经是机器能理解的指令了,只是还没把多个目标文件链接成完整的可执行程序。

编译和汇编的核心区别

我给你提炼两个关键差异:

  • 处理对象与目标不同:
    • 编译阶段:输入是高级语言(C++),输出是汇编语言。它要处理高级语言的语法、语义,做各种优化(比如循环展开、常量折叠),把C++里的类、函数、引用这些抽象概念,转化成汇编里的寄存器操作、内存访问、标签跳转。
    • 汇编阶段:输入是汇编语言,输出是机器码(目标文件)。它几乎是“直译”——每一条汇编指令对应一个机器码,不需要处理高级语言的复杂逻辑,只负责把人类可读的汇编转成机器能跑的二进制。
  • 与硬件的绑定程度不同:
    • 编译阶段的前端(处理语法)是和语言绑定的,但后端(生成汇编)才和CPU架构绑定;
    • 汇编阶段完全和CPU架构绑定——x86_64的汇编不能在ARM上汇编,反之亦然,因为不同CPU的指令集完全不一样。
举个实际操作的例子

你可以自己动手试一下:

  1. 写一个简单的main.cpp:
#include <iostream>
int main() {
    int a = 1, b = 2;
    std::cout << a + b << std::endl;
    return 0;
}
  1. 用g++ -S main.cpp生成main.s,打开这个文件就能看到完整的汇编代码;
  2. 再用g++ -c main.cpp生成main.o,用objdump -d main.o可以反汇编这个目标文件,看到里面的机器码对应的汇编指令(和main.s差不多,但已经是二进制形式了)。

内容的提问来源于stack exchange,提问作者pasha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:14:24