Linux C语言编程(上篇) | gcc的使用

嵌入式软件开发主要使用C语言开发,编译过程称为交叉编译 —— 在PC机上编译出可以在嵌入式处理器上运行的程序,在真正进入嵌入式开发前,先来了解下如何使用gcc+make编译C语言工程,如何用gdb调试工程~

1.C编程流程

1.1.编辑源文件(.c)

使用文本编辑器(比如vim)编辑C语言源文件(.c)和头文件(.h)

1.2.编译源文件

使用编译工具编译之前编写的所有C语言源文件,生成可执行程序,这一步是重中之重。

1.3.运行可执行程序

1.4.调试程序

2.编译器 —— gcc

这部分是整个C语言编程的核心部分之一,这部分就深入探究编译器是如何将C源文件编译为可执行程序的~

2.1.gcc简介与安装

GCC全名GNU Compiler Collection,GNU编译器套装,GCC之前的原名叫GNU C Compiler,最初仅仅是一个C编译器,但是经过后来的发展,它可以处理c++,甚至Fortran、Pascal等,所以改名为GNU编译器套装。
GCC项目是GNU项目的关键部分,是以GPL及LGPL许可证发行的自由软件,是100%的免费软件,所以可以舒服的供我们使用。
当然对于嵌入式开发最重要的是:GCC是一个交叉编译器,这部分留到进入嵌入式开发再具体探索~
杂谈 | Why RTOS & The Art Of Coding & Machine Learning & Linux这篇文章中的Linux部分介绍到,Linux内核与GNU项目共舞才造就了如今强大的Linux,GCC作为GNU项目的关键部分,在Linux发行版一般都已经包含,可以使用命令gcc -v查看当前系统gcc版本, 比如我的Ubuntu16.04LTS:
在这里插入图片描述

如果系统没有安装gcc,可以使用命令sudo apt-get install gcc安装。

2.2.gcc编译流程

gcc编译过程可以分为四个过程:

  • 预处理:对各种预处理命令进行处理,包括头文件的包含,宏定义,条件编译等预处理指令;
  • 编译:对预处理完的文件进行编译,每个文件生成对应的汇编代码;
  • 汇编:将汇编代码转换为机器代码;
  • 链接:将所有生成的机器代码以及依赖库进行链接,生成可执行文件。

2.3.使用gcc编译 —— 由深到浅

使用一个经典的hello world来说明如何使用gcc进行编译:

2.3.1.编辑c源文件

使用vim编辑hello.c:

细心的小伙伴会发现,在windows下main函数里都是int main(void),然而这里却变成了int main(int argc, char *argv[]),首先根据C语言的语法,括号里的是main函数的参数,但因为windows下是使用图形化界面的,所以main函数一般是void,表示参数为空,但是Linux下都是使用命令行的,在执行可执行程序的时候可以给main函数传入参数,所以为了接收参数,写为这样的形式。

  • 第一个参数argc表示传入main函数的参数,这个值往往是不确定的,所以这个值在执行的时候不需要用户指定,由系统自动给定;
  • 第二个参数argv是一个字符串指针,是实际用户传入的参数。

特别注意的是:文件名本身也是一个参数!!!

2.3.2.预处理

使用gcc -E 源文件对源文件进行预处理,-E参数表示gcc在预处理之后停止编译,为了方便查看预处理的文件,使用-o 生成的文件名指明生成的文件名,所以使用命令:gcc -E hello.c -o hello.i

执行指令后可以看到hello.c源文件进行了预处理,查看hello.i,第一行#include <stdio.h>被替换为stdio.h文件中的内容,其它内容没有变,也没有生成别的文件。

2.3.3.编译预处理的文件,生成汇编文件

使用gcc -S 预处理后的文件对预处理后的文件进行编译,并生成汇编文件hello.s-S参数表示只进行编译而不进行汇编,只生成汇编文件,所以使用命令:gcc -S hello.i -o hello.s

查看生成的汇编文件内容,其中都是汇编指令和数据:

2.3.4. 汇编生成的汇编文件,生成目标文件

使用参数-c将汇编代码进行汇编编译,生成二进制目标文件,使用命令gcc -c hello.s -o hello.o

2.3.5. 链接所有的文件及库文件,生成可执行程序

注意上一步中生成的二进制目标文件只是单个源文件对应的目标文件,不是可执行程序,这个文件中还使用了标准库stdio,所以还需要将库依赖文件进行链接,生成可执行程序(默认文件名a.out),使用命令gcc hello.o -o hello

2.3.6. 执行可执行程序(注意main参数)

因为之前编写程序的时候我们是将 main函数传入的第一个字符串参数打印,所以在执行的时候要传入参数,使用命令./hello hello,world

来简单总结一下上面的这些步骤及gcc参数的含义:

参数 描述
-E 对源文件进行预处理
-S 对预处理文件生成汇编文件
-c 对汇编文件进行汇编编译,生成目标文件
-o 指定输出文件名

讲到这个时候,各位小伙伴是不是对C语言的编译过程有所了解了呢?在Windows中简单的单击背后,竟然隐藏着如此多的学问~但是这个过程不免有些繁琐,在实际使用的时候,其实上面整个流程可以简化为两个流程:

  • 编译源文件,生成目标文件gcc -c <源文件名> -o <目标文件名>,在此处使用命令gcc -c hello.c -o hello.o

-链接所有的目标文件,生成可执行程序gcc <目标文件名> -o <可执行程序名>,此处使用命令gcc hello.o -o hello

可以看到这两步就可以完成之前的工作,甚至,我们还可以一行搞定gcc <源文件名> -o <可执行程序名>,此处使用命令gcc hello.c -o hello

我们再来粗暴一点,直接使用默认文件名a.out好了:gcc <源文件>,此处使用命令gcc hello.c

2.4.使用gcc编译 —— 常用编译选项

gcc有超过100个可用选项,主要有:

  • 总体选项
  • 告警和出错选项
  • 优化选项
  • 体系结构相关选项

2.4.1.总体选项

参数 描述
-E 对源文件进行预处理(.i)
-S 对预处理文件生成汇编文件(.s)
-c 只编译不链接(或者对汇编文件进行汇编编译),生成目标文件(.o)
-o 指定输出文件名
-v 打印出编译器内部编译各过程的信息以及编译器版本
-g 在可执行程序中包含调试信息

2.4.2.告警和出错选项

参数 描述
-w 关闭所有告警
-Wall 允许gcc提供所有有用的报警信息
-Werror 把所有告警信息转化为错误信息

2.4.3.库依赖选项

在c语言中库指的就是一些头文件(.h)和库文件(.so或者.a),Linux下大多数头文件都在/usr/include/目录下,库文件在/usr/ib/目录下,若头文件或库文件不在默认目录或者源文件所在目录,需要在编译时加上对应选项

参数 描述
-I(大写i)添加头文件搜索路径
-L 添加库文件搜索文件
-l(小写L) Linux库文件以Lib开头,用-l参数库时省略lib三个字母

2.5.使用gcc编译 —— 查看帮助

可以使用man+<选项>+名称命令函数帮助:

参数 描述
i 在指定节中查找(1-系统命令,2-系统调用,3-C库函数)
-k 关键词

猜你喜欢

转载自blog.csdn.net/Mculover666/article/details/84839258