编译器g++

g++是GNU编译工具集(GCC)中的一个组件,用来编译C++语言写的源文件。

C++源文件可执行文件的编译过程,有如下几个步骤,g++提供了很多编译选项,可以让我们控制整个编译过程:

  • 预编译(g++选项 -E)结果直接输出到控制台
  • 编译 (g++选项 -S)结果保存为.s文件,汇编文件
  • 汇编 (g++选项 -c)结果保存为.o文件,目标文件(object file)
  • 链接 (g++选项 没有) 链接后结果就是可执行文件了

使用这些选项,我们就可以让编译在某一步结束之后停下来,输出那一步的结果。

编译既可以指整个从源文件到可执行文件的过程,也可以只是上面的第二步,大家注意通过上下文分辨。

预编译

这一步会把包含的头文件展开,定义的宏全部替换,比如下面这个例子:

#define ONE 1
#define TWO 2

int add_one_two(){
  return ONE + TWO;
}

保存为add.cpp,使用命令g++ -E add.cpp编译,输出结果如下:

# 1 "add.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "add.cpp"

int add_one_two(){
  return 1 + 2;
}

或许你会问,怎么没有#include,没有main函数啊?

没有#include是因为这个例子很简单,没有用到其他文件里面的声明或定义。没有main函数的原因是,那玩意是链接那一步才需要的,就好比我们做个炒鸡蛋是需要一个锅的,但是在打鸡蛋这一步只要个碗就好了。打鸡蛋相当于预编译,不需要锅;而炒鸡蛋就相当于链接,是需要一个锅的,输出就是可执行文件——炒好的鸡蛋了。

怎么样,很好玩吧。

当然那两个东西也可以有,给大家一个练习吧,把上一篇博客里面那个hello world程序用这个步骤实验一下,结果太长我不贴出来了,不过你一定要试一下阿,一定会吓你一跳的。

前面那些东西是#include <iostream>干的好事,预编译会把iosteam里面#include的文件和它自身的内容全部展开,这也算是个查看源文件的方法吧,而且看的仔细的话你会发现cout是一个模板类的实例(instance)。如果你看不懂,没关系,慢慢来,以后我会深入的。

编译

这一步是把预编译好的文件翻译成汇编语言,生成一个.s文件。是的,预编译后的文件还是人看的,汇编语言就已经是半兽人了;而整个编译过程确实是个翻译的过程——从高级语言到机器语言的翻译过程。发明一门新语言是个相反的过程,不过可以从汇编开始。

下面是个简单的求两个整数的和的函数:

int add(int a, int b){
  return a + b;
}

使用命令g++ -S add.cpp,生成add.s,add.s内容如下:

	.file	"add.cpp"
	.text
	.globl	_Z3addii
	.type	_Z3addii, @function
_Z3addii:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	%edi, -4(%rbp)
	movl	%esi, -8(%rbp)
	movl	-8(%rbp), %eax
	movl	-4(%rbp), %edx
	addl	%edx, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	_Z3addii, .-_Z3addii
	.ident	"GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
	.section	.note.GNU-stack,"",@progbits

刚开始接触汇编确实会有些头大,不过看多了就好了。如果你想成为编程高手,那么汇编语言是必须要能看懂的,例子点击进入( 例子一例子二),不一定要能写,但一定要能看懂。

学汇编的好处还有:更好的理解C++中的指针和引用,理解函数调用,参数传递,理解栈、栈帧,等等,更多内容也是以后深入吧。迫不及待想了解汇编的朋友可以看看这篇博客,真的不难哦(猛击进入)。这个系列博客也不错,不过主题不是汇编(猛击进入)。

汇编

这一步也是翻译,把上一步的汇编语言的.s文件翻译成机器语言的.o文件,这个文件是个二进制文件,已经不是人看的了。想看的话当然有办法,可以使用类似objdump之类的工具反汇编查看。

生成的.o文件叫做目标文件,英语是object file,每个源文件(注意不是头文件哦)在编译过程中都会生成一个对应的目标文件,这样对于一个文件的反汇编调试会变得简单一点,因为目标文件经过最后一步(链接)后,通常会变得很大,就比较难调试了。

更深入点的内容可以参考我之前的一篇博客:)点我进入

链接

这一步是把上一步中生成的所有目标文件整合在一起,链接需要的库文件,好比现在要做蛋炒饭,汇编一步分别炒好了鸡蛋、蒸好了米饭,链接这一步就是把两个材料混在一起炒匀了,然后再加点调料(其他库文件)。具体内容也可以参考我那篇博客。

总结

当然g++提供的编译选项远远不止上面那几个,g++的帮助文件(man)的概要部分是这样的:

       gcc [-c|-S|-E] [-std=standard]
           [-g] [-pg] [-Olevel]
           [-Wwarn...] [-pedantic]
           [-Idir...] [-Ldir...]
           [-Dmacro[=defn]...] [-Umacro]
           [-foption...] [-mmachine-option...]
           [-o outfile] [@file] infile...


       Only the most useful options are listed here; see below for the
       remainder.  g++ accepts mostly the same options as gcc.

这篇博客介绍的内容只是第一个中括号里面的选项而已,后面的中括号里面还有各种其他选项,比较常用的有调试选项,警告选项,代码优化选项,-o选项。所以说g++是在是很强大,上手容易,要用好需要多练习。

放在中括号里的选项表示这些选项是可选的,只有后面infile是必须的,如果没有选项,比如我上一篇博客里面那样:g++ hello.cpp,g++会按照默认的选项编译出可执行文件,默认选项是什么我也不知道,我错了。。。

后面那句英语翻译过来(红色部分)是:只有比较有用的选项列了出来,剩下的在后面(我只贴了帮助文件的一小部分,后面还有很多没贴,大家用这个命令自己看吧:man g++,pageup,pagedown翻页)。g++接受和gcc基本类似的选项。(gcc是GNU的C语言的编译器)

我们在编译的整个过程中,会因为各种各样的问题,g++会给我们报各种错误。主要集中在编译和链接两步。

写程序时候的语法错误和声明问题会在编译这一步给出。定义问题会在链接这一步给出。声明和定义是两个问题,比较需要注意,我以后再深入了。


好了,g++暂时介绍到这吧,最后说一点题外话。

从我写上上一篇博客《几点学习linux编程的建议》写到最后发现自己离题万里开始,我就知道我需要写个系列了,系列的主题就是那篇博客的第一句话:”我个人用了3、4年linux,从当初的小菜鸟到现在的大菜鸟,积累了一些经验,现在分享给大家,尤其是初学者。“

这里的初学者主要是大学一二三四年级的学生朋友,包括没有编程经验到只有windows编程经验学生朋友。个人觉得吧,windows编程是个舒服的牢笼,linux编程是充满风雨的世界。再舒服的牢笼也是牢笼,总有一天总会让你觉得自己是被束缚的;而在风雨的世界里面,你却可以建筑一个比牢笼舒服百倍的自己的城堡。通过这个系列,我希望我能帮助初学者朋友在linux的世界里面搭个自己的小木屋,至于建城堡,就看各位的想象力和创造力了。

最后,希望大家多动手,多练习。如果不知道拿什么练习,请参考我上一篇博客:)

祝你好运。

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值