Chinaunix首页 | 论坛 | 博客
  • 博客访问: 287867
  • 博文数量: 182
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1292
  • 用 户 组: 普通用户
  • 注册时间: 2015-05-06 19:02
个人简介

让一切的准备都完美演出,让所有的努力都美好落幕

文章分类

全部博文(182)

文章存档

2016年(60)

2015年(122)

我的朋友

分类: LINUX

2015-07-23 20:50:46

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函数的原因是,那玩意是链接那一步才需要的,就好比我们做个炒鸡蛋是需要一个锅的,但是在打鸡蛋这一步只要个碗就好了。打鸡蛋相当于预编译,不需要锅;而炒鸡蛋就相当于链接,是需要一个锅的,输出就是可执行文件——炒好的鸡蛋了。
前面那些东西是#include <iostream>干的好事,预编译会把iosteam里面#include的文件和它自身的内容全部展开,这也算是个查看源文件的方法吧,而且看的仔细的话你会发现cout是一个模板类的实例(instance)。
编译
这一步是把预编译好的文件翻译成汇编语言,生成一个.s文件。是的,预编译后的文件还是人看的,汇编语言就已经是半兽人了;而整个编译过程确实是个翻译的过程——从高级语言到机器语言的翻译过程。发明一门新语言是个相反的过程,不过可以从汇编开始。
下面是个简单的求两个整数的和的函数:
  1. int add(int a, int b){  
  2.   return a + b;  
使用命令g++ -S add.cpp,生成add.s,add.s内容如下:
  1. .file   "add.cpp"  
  2.     .text  
  3.     .globl  _Z3addii  
  4.     .type   _Z3addii, @function  
  5. _Z3addii:  
  6. .LFB0:  
  7.     .cfi_startproc  
  8.     pushq   %rbp  
  9.     .cfi_def_cfa_offset 16  
  10.     .cfi_offset 6, -16  
  11.     movq    %rsp, %rbp  
  12.     .cfi_def_cfa_register 6  
  13.     movl    %edi, -4(%rbp)  
  14.     movl    %esi, -8(%rbp)  
  15.     movl    -8(%rbp), %eax  
  16.     movl    -4(%rbp), %edx  
  17.     addl    %edx, %eax  
  18.     popq    %rbp  
  19.     .cfi_def_cfa 7, 8  
  20.     ret  
  21.     .cfi_endproc  
  22. .LFE0:  
  23.     .size   _Z3addii, .-_Z3addii  
  24.     .ident  "GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"  
  25.     .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++会给我们报各种错误。主要集中在编译和链接两步。
写程序时候的语法错误和声明问题会在编译这一步给出。定义问题会在链接这一步给出。声明和定义是两个问题,比较需要注意。

阅读(1093) | 评论(0) | 转发(0) |
0

上一篇:学习linux编程2

下一篇:学习linux编程4

给主人留下些什么吧!~~