浅析Linux开发工具之gcc/g++

在windows开发平台,我们用惯了vc、vs等IDE(集成开发环境),在编译好源代码之后,按下相应按钮,IDE就会为我们完成编译,链接的过程。然而在Linux平台下,却没有这么方便的开发环境,很多事情都需要我们亲力亲为,为此我们要了解两款编译器:gcc/g++,它们分别是GNU的c/c++编译器。
下面,来具体了解一下这两款编译器:
1、gcc/g++的安装
在终端输入两条命令即可:
(1)安装gcc
Debian系列:sudo apt-get install gcc
RedHat系列:sudo yum install gcc
(2)安装g++
Debian系列:sudo apt-get install g++
RedHat系列:sudo yum install gcc-c++

PS:Debian系列的系统可以用一条命令:sudo apt-get install build-essential来安装gcc、g++、make这一套工具。

2、gcc/g++的编译过程
我们都知道,编写好的源代码在生成可执行程序的过程中需要以下四步:预处理、汇编、编译、链接,同样的,我们的工具gcc/g++在为我们生成可执行程序的过程中也经历了上述四步,下面我们来具体看看这四个执行步骤。
下文图片中出现的Makefile文件是我为了方便我的编译创建的一个文件,不用理会。
这里以gcc举例,g++与之类似,首先编写源文件:

先用touch命令创建我们要编写的源文件:
这里写图片描述
接着编辑源文件的内容:

//tran.h
1 #include <stdio.h>
2 
3 void tran();
//tran.c
1 #include "tran.h"
2 
3 void tran()
4 {
5     printf("this is tran\n");
6 }       
//test.c
1 #include "tran.h"
2 #define NUM 1234
3 
4 int main()
5 {
6     printf("%d\n", NUM);
7     tran();
8     return 0;
9 }

然后来看看文件编译后的状态(这儿只看test.c的,tran.c的与之相似,头文件无法编译)

(1)预处理,生成.i的文件
预处理:这个步骤为我们完成的工作是宏替换、头文件展开、条件编译、特殊符号的处理。使用的命令是:
gcc -E x.c -o x.i //这里的x指的是依赖的文件的文件名和要生成的文件名
-E:该选项的作用用是让 gcc 在预处理结束后停止止编译过程。
-o:指定生成的文件名。
例如:
这里写图片描述

这里写图片描述
可以看到这里已经生成了一个名字为test.i的文件:

用cat命令看一下文件test.i的内容:
这里写图片描述
可以看到,头文件tran.h已经被替换为上面那些乱七八槽的东西了,宏NUM也被替换为它对应的数字1234。

(2)编译,生成汇编文件.s
编译程序,所要作的工作就是通过词法分析、语义分析、符号汇总和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。使用的命令是:
gcc -S x.i -o x.s //这里的x指的是依赖的文件的文件名和要生成的文件名
-S:该选项只进行编译而不进行汇编,生成汇编代码。
-o:指定生成的文件名
例如:
这里写图片描述

这里写图片描述
可以看到已经生成了名为test.s的文件

用cat命令看一下test.s的内容:
这里写图片描述
可以看到确实是生成了汇编代码

(3)汇编,生成目标文件 .o文件
汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程,也就是说把汇编代码转换为二进制文件(即目标文件),目标文件中所存放的是与源程序等效的目标的机器语言代码。
目标文件由段组成:一个目标文件中至少有两个段:
代码段:主要包含的是程序的指令。该段一般是可读、可执行、不可写。
数据段:主要存放程序中的全局变量或静态的数据。一般数据段都是可读、可执行、可写 。
这儿使用的命令是:
gcc -c x.s -o x.o
-c:将汇编代码生成二进制的目标文件
-o:指定生成的文件名
例如:
这里写图片描述

这里写图片描述
可以看到已经生成了文件tets.o

(4)链接,生成可执行程序
由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。

链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。

根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:
(1)静态链接:在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。(个人备注:静态链接将链接库的代码复制到可执行程序中,使得可执行程序体积变大)
(2)动态链接:在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。(个人备注:动态链接指的是需要链接的代码放到一个共享对象中,共享对象映射到进程虚地址空间,链接程序记录可执行程序将来需要用的代码信息,根据这些信息迅速定位相应的代码片段。可移植性差)
这儿使用的命令是:
gcc -o x x1.o x2.o ……
这儿的-o后面的x是生成的可执行程序的名称,x1.o,x2.o……是所有需要被链接到一起的.o文件。
例如:
这里写图片描述
这儿省略了tran.o的生成过程

这里写图片描述
可以看到已经生成了可执行文件test

这里写图片描述

3、gcc/g++的选项扩展
当然,我们平时不用这么麻烦的一步步执行下来,上面是为了展示一下gcc的编译过程,平时我们在编译.c文件时,直接使用命令:
gcc -o file file1.c file2.c ……
file是生成的可执行程序的名字,file1.c,file2.c是要用到的源文件。

下面列出一些常见的gcc选项:
1、-O0 -O1 -O2 -O3 译器的优化选项的4个级别,-O0表示示没有优化,-O1为缺省值,-O3优化级别最高高
2、-w 不生生成任何警告信息
3、-Wall 生成所有警告信息。
4、-g 生成调试信息。GNU 调试器可利用用该信息。
5、-static 此选项将禁止使用动态库,所以,编译出来的东西,一般都很大。
6、-share 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/526152.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux权限的简单剖析

一、权限是什么 权限&#xff08;privilege&#xff09;是指某个特定的用户具有特定的系统资源使用权力。举个简单的例子&#xff0c;夏日炎炎&#xff0c;你看到路边有卖西瓜的&#xff0c;你想要吃西瓜&#xff0c;你就得买它&#xff0c;买它其实就是获取你对西瓜的使用权限…

Linux文件的三种时间属性

一、Linux文件时间属性的分类 我们在用windows系统时&#xff0c;在查看磁盘文件时&#xff0c;经常会看到文件或目录的后面有一个时间信息&#xff0c;这个是文件在磁盘上别创建的时间。其实&#xff0c;在windows系统中&#xff0c;文件还有文件的修改时间、访问时间两个时间…

浅析Linux开发工具之Makefile

一、什么是Makefile 在windows平台下&#xff0c;有很多的IDE供我们使用&#xff0c;我们不会去考虑怎么把一个很大的工程编译链接为一个可执行程序&#xff0c;因为这些事IDE都为我们做了&#xff0c;而在Linux平台下&#xff0c;我们并没有这么高端的IDE供我们使用&#xff…

嵌入式面试准备

题目都摘于网上 嵌入式系统中经常要用到无限循环&#xff0c;如何用C编写死循环 while(1){}或者for(;&#x1f609; 内存分区 代码区&#xff0c;全局区&#xff08;全局变量&#xff0c;静态变量&#xff0c;以及常量&#xff09;&#xff0c;栈区&#xff0c;堆区 const关键…

C语言extern与static修饰变量

extern和static在C语言里面的作用这里就不做过多的阐述了&#xff0c;下面直接通过一个小程序来看一看他们修饰的变量的特性。 #include <stdio.h>int count 3;int main() {int i 0, count 2, sum 0;for (i 0; i < count; i 2, count){static int count 4;cou…

函数值的交换

《函数值的交换》 交换函数的几种方式&#xff1a; (1) //error int Swap1(int a,int b) { int tmp; tmp a; a b; b tmp; return 0; } 在函数Swap1中&#xff0c;a和b的地址的值并没有交换。只是把10和20赋给了a和b&#xff0c;a和b原本的值并没有改变。 (2) #…

数组的下标越界

《数组下标越界》 数组定义的一般形式为&#xff1a;类型说明符 数组名[常量表达式] [常量表达式]这两个常量表达式分别指定了二维数组的行数和列数&#xff0c;程序编译时据此向内存申请空间。 引用二维数组的格式为&#xff1a;数组名[行下标] [列下标]&#xff0c;下标都是从…

指针的加减法计算

(1) 指针&#xff1a;&#xff08;p&#xff09;表示加一个单元格&#xff08;单元格的字节随类型而定&#xff09;#include<stdio.h>int main(){int arr[10]{1,2,3,4,5,6};int *p arr;p;printf("%d %d\n",arr[0],arr[1]);return 0;}(2) 指针加数字&#xff1…

字符串在指针和数组上赋值的区别

1 #include<stdio.h> 2 int main() 3 { 4 char *str1 "abcde";// 字符串常量 5 char str2[] "abcde";// 字符数组 6 str1[0] x;//error 7 str2[0] x; 8 return 0; 9 } 注&#xff1a;代码运行到第6行崩溃 *str1是一个指…

继承与多态(一)

目录 一、继承的概念&#xff1a; 二、公有继承 三、私有继承 四、保护继承 五、保护继承与保护成员的访问 一、继承的概念&#xff1a; 在C中可以用已有的类来定义新的类&#xff0c;新类将继承原有类的全部特性&#xff0c;原有类称为基类&#xff08;父类&#xff09;&…

对象的使用

目录 一、对象指针 二、对象引用 三、对象数组 四、动态对象 五、this指针 六、组合对象 一、对象指针 定义&#xff1a;占用一块连续的内存区域&#xff0c;由此可以使用一个指向对象的指针来访问对象。它指向存放该对象的地址。 优点&#xff1a; &#xff08;1&a…

友元

概念&#xff1a;在C中&#xff0c;类具有封装性和隐蔽性&#xff0c;只有类的函数成员才能访问类的私有成员&#xff0c;程序中的其他函数是无法访问类的私有成员&#xff0c;友元为类的封装隐藏开了一个小孔&#xff0c;外界可以访问类内部的一些属性。如果某个对象说明为某个…

常对象与常成员

一、常对象 概念&#xff1a;如果某个对象不允许修改&#xff0c;则该对象称为常对象。 PS&#xff1a; &#xff08;1&#xff09;不允许常对象调用任何类的成员函数&#xff0c;而且常对象一旦定义&#xff0c;在其生存期内不允许修改&#xff0c;否则导致编译错误。 &am…

指针在数组里的加法

在C语言中&#xff0c;指针与数组经常放在一起使用&#xff0c;很多情况下数组和指针可以互相转换。 //伪代码 int arr[10] {0,1,2,3,4,5,6,7,8,9};int * p arr;arr[i] * (pi);//i是大于0小于数组长度-1的任何正整数*(arr1) arr[i]; 数组和指针的不同&#xff1a; &…

单链表(带头节点)

带头结点单链表的内存分布情况 头文件 #pragma once //带头节点的单链表 //单链表尾节点的next为NULL //List为一条链表&#xff1b;Node* 一个节点的地址 typedef struct Node {int data;//数据Node *next;//下一个节点的地址 }Node ,*List ;//List Node *//初始化 void Ini…

双向链表(带头结点)

带头结点双向链表的内存分布情况 头文件 #pragma once //双向链表 typedef struct DNode {int data;DNode* next;DNode* prio; }DNode , *DList ;//初始化 void InitList(DList plist);//头插法 bool Insert_head(DList plist,int val);//尾插法 bool Insert_tail(DList plist…

给出一个数:(1)求解有几位数,(2)分别输出每一位数字(3)按逆序输出各位数字

目录 &#xff08;1&#xff09;求解有几位数 (2)分别输出每一位数字 (3)按逆序输出各位数字 &#xff08;1&#xff09;求解有几位数 #include<stdio.h>unsigned int GetFigures(int n) {unsigned int figures 0; while(n!0){n / 10;figures;}return figures; }int …

c++两个数组对比去掉重复的元素_LeetCode 题解 | 167.两数之和 II 输入有序数组...

点击上方蓝字设为星标下面开始今天的学习&#xff5e;力扣 167.两数之和 II - 输入有序数组(点击文末阅读原文查看题目)题目描述给定一个已按照 升序排列 的有序数组&#xff0c;找到两个数使得它们相加之和等于目标数。函数应该返回这两个下标值 index1 和 index2&#xff0c;…

循环队列(线性)

队列遵循先进先出的原则&#xff0c;一般从队尾插入&#xff0c;从队头删除。指向队头的指针称为front&#xff0c;队尾指针为rear。&#xff08;目的是为了方便插入和删除元素&#xff09; 假设队列一共有五个元素&#xff0c;当没有元素的时候&#xff0c;front和rear指针都指…

如何c51和mdk共存兼容_2020年网站如何做seo优化

原标题&#xff1a;2020年网站如何做seo优化2017年SEO优化已不再是简单按部就班的去做优化了&#xff0c;随着搜索引擎算法的不断改进和用户搜索习惯的变化&#xff0c;如今的SEO优化更复杂了&#xff0c;那么除了传统的页面元素外&#xff0c;SEO优化还应该注意哪些问题呢?今…