目录

1、可执行文件(程序)

2、程序的编译链接过程

2.1、预处理阶段

2.2、编译阶段

2.3、汇编阶段

2.4、链接阶段

3、在gcc编译器上进行程序编译运行实操

3.1、gcc安装

3.2、预处理:gcc  -E main.c  -o  main.i

3.3、编译:gcc  -s  main.i  -o  main.s

3.4、汇编:gcc  -c  main.s  -o  main.o

3.5、链接:gcc  所有需要被链接的目标.o文件  -o  main

3.6、执行可执行程序

4、一步编译执行:gcc  -o  可执行文件名  所有依赖的源文件

5、make命令及makefile文件编写——管理工程实现自动化编译

6、gdb代码调试

6.1、生成Debug可调试版本:gcc  -o  可执行文件名  源文件  -g

6.2、进入程序调试:gdb Debug版可执行文件名

6.3、下断点:b 目标代码行号

6.4、从断点处开始运行调试与运行:r、n

6.5、打印数组内容:p  数组名

6.6、查看断点信息:info  break

6.7、删除断点:delete  断点号

6.8、退出调试:q


1、可执行文件(程序)

我们编写代码的目的就是最终要能运行我们的代码,去完成某些操作。要想使代码运行起来,就要让代码文件变成一个可执行的文件(程序)。所以我们要先了解一下什么是可执行文件。

可执行文件:在Windows操作系统中,扩展名为:*.exe,*bat等的文件是可执行文件,可执行文件由指令和数据构成。Linux是靠文件属性来判断是否可执行。

但是,可执行程序不是仅仅在Windows中将文件后缀名修改为.exe或在Linux中将文件属性添加上x就变成一个可执行文件了

众所周知,计算机只认识机器码,也就是01二进制,而我们所用C/C++属于高级语言,计算机不能直接识别、运行。从C代码程序文件变成一个计算机可直接运行的文件,这其中需要经历预处理、编译、汇编、链接的重要过程,并不止是在编程软件上点一下编译、点一下运行就好了。

2、程序的编译链接过程

C程序编译链接的过程无论是在Windows上还是Linux上,都是一样的,只不过文件后缀不同,如经汇编后的机器码文件,也就是目标文件,在Linux上的后缀为.o,Windows上的后缀为.obj,还有可执行文件等。

注意:Windows系统以文件后缀名区分文件类别,Linux系统以文件属性区分文件。在Linux系统上文件代码文件有后缀,只是因为C编译器需要以后缀名来判断其是否是C语言程序(Linux常用命令-2.3.2普通文件)。

2.1、预处理阶段

主要工作是将头文件插入到所写的代码中,生成扩展名为“.i”的文件替换原来的扩展名为“.c”的文件,但是原来的文件仍然保留,只是执行过程中的实际文件发生了改变。此外,还有如下操作:
        a) 删除所有的“#define”,并且展开所有的宏定义;
        b) 处理所有的条件预编译指令,“#if”、“#ifdef”、“#endif”等;
        c) 处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置;
        d) 删除所有的注释;
        e) 添加行号和文件名标识,以便于编译器产生调试用的符号信息及编译时产生编译错误和警告时显示行号;
        f) 保留所有的#pragma 编译器指令,因为编译器需要使用它们。

2.2、编译阶段

主要工作是将 .i 文件中的代码翻译成特定汇编语言

编译器首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作(词法分析、语法分析、语义分析),在检查无误后,编译器把代码翻译成汇编语言,同时将扩展名为“.i”的文件翻译成扩展名为“.s”的文件。

2.3、汇编阶段

主要工作:将上一步的汇编代码转换成机器码(machine code),这一步产生的文件叫做目标文件.o文件,是二进制格式。

2.4、链接阶段

主要工作:链接过程将多个目标文件以及所需的库文件(.so等)链接成最终的可执行文件。在项目中,我们编写的代码文件不止一个,所以需要将最终可执行程序依赖的所有目标文件进行链接。

3、在gcc编译器上进行程序编译运行实操

示例C程序文件:

main.c:此时add函数定义在main函数之后,且前方无声明,有错。

3.1、gcc安装

命令:sudo apt install gcc。若失败,先sudo apt-get install update,在sudo apt install gcc

3.2、预处理:gcc  -E main.c  -o  main.i

在执行完 gcc  -E main.c  -o  main.i 命令后,系统将main.c文件进行预处理,未对代码是否正确进行检测,生成main.i文件。完成了对头文件stdio.h的插入。此时若查看main.i文件就会发现其中多出了几百行内容,就是因为插入了头文件stdio.h的内容。

3.3、编译:gcc  -s  main.i  -o  main.s

此时,系统对main.i中的代码进行编译,检查其是否出错。若无错,则将代码编译成汇编语言代码,生成main.s文件;若有错,则警告。

根据警告,对代码进行改错,再从头开始进行预处理、编译后,成功生成main.s文件。

并且,对main.s文件进行查看,发现其内容为汇编代码。

3.4、汇编:gcc  -c  main.s  -o  main.o

1、注意,此时 -c 是小写若为大写 -C,并且因为main.c是一个有完整功能的程序文件,此时其不需要进行链接,其生成的目标二进制文件main.o就是可执行的。并且当前可执行的main.o不能再被链接

此时,系统将汇编语言文件main.s汇编成目标二进制文件main.o,此时main.o已具有可执行权限x。

执行:命令:./main.o。代码执行1+2的结果为3。

2、gcc  -c  main.s  -o  main.o

此时生成的main.o文件是不可以直接执行的,不具有x权限。

此时,若查看main.o文件的内容,会发现其内容不能被vi/vim编辑器解析。

3.5、链接:gcc  所有需要被链接的目标.o文件  -o  main

若还有其他需要被链接的文件,则那些文件都要经过上述操作,生成.o文件,再在链接过程最终链接成为一个整体的可执行文件;若没有,就只链接一个文件就行。

3.6、执行可执行程序

可执行程序的执行与命令一样(命令就是系统自带的可执行程序)。只不过常用命令在系统/bin目录下存放着,可以直接在终端输入命令就可以执行我们生成的可执行程序在我们当前所在的目录下,如果我们要执行生成的可执行程序就要使用 ./可执行程序名  格式进行执行。目的是告诉系统该可执行程序在当前目录下。如:

如果我们想要像命令一般执行 main 可执行程序,可以将 main可执行程序 移动到 /bin 目录下,这样就可以和命令一样使用main。但需要注意,main可执行程序就不可以和 /bin 目录下的命令同名,不然会导致出错

4、一步编译执行:gcc  -o  可执行文件名  所有依赖的源文件

测试文件:

add.h:

add.c:

main.c:

上述过程比较复杂,所以系统还提供了将所有最终可执行程序依赖的源文件进行预处理、编译、汇编、链接的一步方法。只需在 gcc -o 可执行文件名 命令后添加上所有依赖的源文件就可以了。如:

使用命令gcc -o main  main.c add.c

5、make命令及makefile文件编写——管理工程实现自动化编译

安装make命令:sudo apt install make

对于较大的项目或工程中,最后生成的可执行文件依赖的源文件特别多的话,也可以选择使用编写makefile文件的方式,对所有源文件进行自动编译。

测试文件:

add.c:

mul.c:

main.c:

makefile文件,其格式如下:

注意:在gcc代码行的缩进需要使用Tab来实现,使用四个空格键是不行的

make命令的使用:在安装好make命令和编写好makefile文件后,直接在终端使用make命令,就可以对所有源文件进行编译链接,得到最终的可执行文件。

此时,main就是最终的可执行文件。

clean的使用命令:make clean

6、gdb代码调试

安装命令:sudo apt install gdb

可执行程序分为Debug版本和Release版本两种,如vs上:

Debug版本:
        Debug版本为可调试版本,生成的可执行文件中包含调试需要的信息,我们作为开发人员,最常用的就是debug版本的可执行文件。
        Debug 版本的生成:    因为调试信息是在编译过程时加入到中间文件(.o)中的,所以必须在编译时控制其生成包含调试信息的中间文件
        gcc -c hello.c -g   ---> 生成包含调试信息的中间文件
        gcc -o hello  hello.o
        或者gcc -o hello  hello.c  -g

Release 版本:
        Release版本为发行版本,是提供给用户使用的版本。用 gcc 默认生成的就是 Release 版本。
        首先将源代码编译、链接生成 Debug 版本的可执行文件,然后通过‘gdb Debug版本的可执行文件名’进入调试模式。

测试文件:

ps.c:程序目标为循环从键盘输入字符串,若字符串与"end"相等,则退出循环。

6.1、生成Debug可调试版本:gcc  -o  可执行文件名  源文件  -g

6.2、进入程序调试:gdb Debug版可执行文件名

例如,使用 gdb ps 命令,进入ps程序调试:

此时,就进入了程序的调试阶段,系统等待调试命令的下达。常用命令如下:

6.3、下断点:b 目标代码行号

例如,此时我们在程序第五行打断点,就使用命令 b 5

6.4、从断点处开始运行调试与运行:r、n

使用 r 命令后,从程序断点处开始运行调试,并使用 n 命令一步步向下执行。

在程序调试过程中,程序显示正在运行的每一行的行号与代码内容。在执行到需要输入的代码时,光标闪烁,等待输入。

6.5、打印数组内容:p  数组名

在输入"end"字符串后,发现程序仍然向下执行,并未break跳出循环,这就发现了程序的漏洞。就可以使用 p  buff 命令,查看buff数组保存的我们输入的字符串到底是不是"end"。

此时发现,buff数组将我们输入的回车也接收进去了,怪不得strcmp(buff,"end")不等于0。

6.6、查看断点信息:info  break

在达成目的后,我们就需要删除断点,而断点的删除需要使用到断点号,若不记得断点号了,就可以使用 info break 命令,查看断点信息,其中就有断点号。

6.7、删除断点:delete  断点号

此时,程序中只有一个断点,且断点号为1,就可以使用 delete 1 命令删除该断点。

6.8、退出调试:q

在调试结束,就可以使用 q 命令退出调试。

Linux系统上C语言程序编写与调试相关推荐

  1. 简单linux蠕虫,清除Linux系统上的蠕虫程序Ramen

    Linux系统中出现了一种称之为Ramen的蠕虫程序.它可能会入侵数千台运行RedHat 6.2/7.0 操作系统的服务器.Ramen利用了两个已知的Linux安全漏洞.它首先利用 RPC.statd ...

  2. linux系统下c语言程序需要改动的地方,如何在Linux系统环境下进行C语言开发

    描述 对于程序设计员来说,makefile是我们绕不过去的一个坎.可能对于习惯Visual C++的用户来说,是否会编写makefile无所谓.毕竟工具本身已经帮我们做好了全部的编译流程.但是在Lin ...

  3. 嵌入式开发基于linux系统的c语言程序开发调试工具

    在学习嵌入式的过程中,我们接触最多的就是Linux环境,而在嵌入式 linux 领域我们最常用的代码调试工具应该就是GDB了,通过简单的学习GDB调试工具,发通过使用它可以有效的解决一些问题. gdb ...

  4. 在LInux系统上安装ImageMagick

    一.ImageMagick的安装背景 项目中需要获得ECG图片,使用心电插件只能生成PDF,因此需要在Linux系统上安装ImageMagick程序将PDF转化成图片 二.ImageMagick介绍 ...

  5. Linux上C语言程序编译过程详解

    点击蓝字 关注我们 因公众号更改推送规则,请点"在看"并加"星标"第一时间获取精彩技术分享 来源于网络,侵删 本文将介绍如何将高层的C/C++语言编写的程序转换 ...

  6. 基于虚拟机Ubuntu系统下C语言简单编写程序

    目录描述 前言 一.修改系统参数 1.查看Ubuntu版本 2.原文件备份 3.下载清华源 二.编写"hello world"C语言程序 1.安装vim 2.建立hello.c 3 ...

  7. 以Linux系统上的gcc为例,解密C语言编译背后的全过程!

    在这个互联网时代,很多人都选择了计算机专业,而只要是计算机专业的小伙伴,可能都会学C语言,但是大家是否都清楚C语言编译的完整过程呢,今天我就带着大家一起来做个解密吧. C语言相对于汇编语言是一种高级语 ...

  8. golang语言的入门基础,及window和linux系统上环境的搭配及运行

    golang语言的入门基础,及window和linux系统上环境的搭配及运行 简介: Go语言是谷歌推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性.Go语言专门针对多处理器 ...

  9. qt creator:一款能够在windows/linux/mac系统上开发c程序的IDE

    qt creator:一款能够在windows/linux/mac系统上开发c程序的IDE 下面是下载地址:http://download.qt.io/official_releases/qtcrea ...

最新文章

  1. 我所了解的Linux运维技术
  2. MySQL二进制日志文件过期天数设置说明
  3. win 10无法启动print spooler服务,提示1068依赖服务或组无法启动
  4. LeetCode_Convert Sorted Array to Binary Search Tree(Java实现)
  5. 苹果供应商:iPhone SE 3 5G和AirPods生产平稳
  6. 弹窗设计UI素材模板|带你了解下弹窗特性
  7. mysql 列转置_MySQL行列转置方法
  8. php无限极 left right,PHP超牛逼无限极分类生成树方法
  9. 软件设计师教程 第5版 下载
  10. JavaScript详细解析
  11. EXCEL中如何撤销工作表保护
  12. 常用计算机故障的判断方法有哪些,常用汽车故障基本诊断方法
  13. 使用微PE制作纯净版装机U盘(纯小白教程)
  14. linux系统安装kms,Linux安装部署KMS服务器
  15. u盘文件无法复制是什么原因?有什么解决方法
  16. TestNG数据驱动
  17. Sonya and Exhibition 【模拟】
  18. MAC虚拟机设备无法连接到它的理想主机控制器
  19. CDH版本Hadoop集群环境搭建详解
  20. 【亡羊补牢】挑战数据结构与算法 第18期 LeetCode 面试题 08.08. 有重复字符串的排列组合(递归与回溯)

热门文章

  1. 作为新人,如何快速融入新团队?用好这8个点
  2. 新四级冲刺需牢记的700核心词
  3. JavaNIO——多线程以及IO模型(笔记)
  4. 【吐血推荐】机器学习/深度学习入门资料汇总及学习建议【入门必看】
  5. 50个经典Sql语句
  6. 黑马毕向东Java课程笔记(day07):面向对象(第三部分)继承+抽象类+模板方法设计模式+接口+final+继承补充(就业班)
  7. 记录--浏览器插件分享(视频倍速播放插件)
  8. python中uppercase是什么意思_Python string.uppercase方法代码示例
  9. iPhone X,XS,XSMax,XR的兼容问题
  10. Ps小技术——通道抠图大法