04 linux之C 语言高级编程

news2024/11/15 4:39:30

gcc和gdb

GNU工具

  • 编译工具:把一个源程序编译为一个可执行程序
  • 调试工具:能对执行程序进行源码或汇编级调试
  • 软件工程工具:用于协助多人开发或大型软件项目的管理,如make、CVS、Subvision
  • 其他工具:用于把多个目标文件链接成可执行文件的链接器,或者用作格式转换的工具。

GCC

GCC简介:

  • 全称为GNU CC ,GNU项目中符合ANSI C标准的编译系统
  • 编译如C、C++、Object C、Java、Fortran、Pascal、Modula-3和Ada等多种语言
  • GCC是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高20%~30%
  • 一个交叉平台编译器 ,适合在嵌入式领域的开发编译

GCC编译器的版本:

  • GNU Compiler Collection
  • C, C++, Objective-C, Fortran, Java, Ada

gcc所支持后缀名解释:

  • .c C原始程序
  • .C/.cc/.cxx C++原始程序
  • .m Objective-C原始程序
  • .i 已经过预处理的C原始程序
  • .ii 已经过预处理的C++原始程序
  • .s/.S 汇编语言原始程序
  • .h 预处理文件(头文件)
  • .o 目标文件
  • .a/.so 编译后的库文件

编译器的主要组件

  • 分析器:分析器将源语言程序代码转换为汇编语言。因为要从一种格式转换为另一种格式(C到汇编),所以分析器需要知道目标机器的汇编语言。
  • 汇编器:汇编器将汇编语言代码转换为CPU可以执行字节码。
  • 链接器:链接器将汇编器生成的单独的目标文件组合成可执行的应用程序。链接器需要知道这种目标格式以便工作。
  • 标准C库:核心的C函数都有一个主要的C库来提供。如果在应用程序中用到了C库中的函数,这个库就会通过链接器和源代码连接来生成最终的可执行程序。

GCC的基本用法和选项

Gcc最基本的用法是∶gcc [options] [filenames]

  • -c,只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件。
  • -o output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。
  • -g,产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项。
  • -O,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。
  • -O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。
  • -I dirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。
  • -L dirname,将dirname所指出的目录加入到程序函数档案库文件的目录列表中,是在链接过程中使用的参数。

GCC的错误类型及对策

  • 第一类∶C语法错误

    错误信息∶文件source.c中第n行有语法错误(syntex errror)。有些情况下,一个很简单的语法错误,gcc会给出一大堆错误,我们最主要的是要保持清醒的头脑,不要被其吓倒,必要的时候再参考一下C语言的基本教材。

  • 第二类∶头文件错误

    错误信息∶找不到头文件head.h(Can not find include file head.h)。这类错误是源代码文件中的包含头文件有问题,可能的原因有头文件名错误、指定的头文件所在目录名错误等,也可能是错误地使用了双引号和尖括号。

  • 第三类∶档案库错误

    错误信息∶链接程序找不到所需的函数库(ld: -lm: No such file or directory )。这类错误是与目标文件相连接的函数库有错误,可能的原因是函数库名错误、指定的函数库所在目录名称错误等,检查的方法是使用find命令在可能的目录中寻找相应的函数库名,确定档案库及目录的名称并修改程序中及编译选项中的名称。

  • 第四类∶未定义符号

    错误信息∶有未定义的符号(Undefined symbol)。这类错误是在连接过程中出现的,可能有两种原因∶一是使用者自己定义的函数或者全局变量所在源代码文件,没有被编译、连接,或者干脆还没有定义,这需要使用者根据实际情况修改源程序,给出全局变量或者函数的定义体;二是未定义的符号是一个标准的库函数,在源程序中使用了该库函数,而连接过程中还没有给定相应的函数库的名称,或者是该档案库的目录名称有问题,这时需要使用档案库维护命令ar检查我们需要的库函数到底位于哪一个函数库中,确定之后,修改gcc连接选项中的-l和-L项。

GCC编译过程

GCC的编译流程分为四个步骤:

  1. 预处理(Pre-Processing)
  2. 编译(Compiling)
  3. 汇编(Assembling)
  4. 链接(Linking)

image

生成预处理代码

$ gcc –E test.c -o test.i

wc命令,查看这两个阶段代码大小:$ wc test.c test.i

9 16 127 test.c

842 1934 16498 test.i

851 1950 16625 总用量
test.i比test.c增加了很多内容,主要是放在系统提供的include文件中的。

生成汇编代码

检查语法错误,并生成汇编文件

$ gcc –S test.c –o test.s

生成目标代码

  • 方法一,用gcc直接从C源代码中生成目标代码:$ gcc –c test.s –o test.o
  • 方法二,用汇编器从汇编代码生成目标代码:$ as test.s –o test.o

生成可执行程序

将目标程序链接库资源,生成可执行程序$ gcc test.s –o test、再运行./test

Gdb调试流程

  • 首先使用gcc对test.c进行编译,注意一定要加上选项‘-g
  • 设置断点后程序在指定行之前停止。
  • 只有在代码处于“运行”或“暂停”状态时才能查看变量值。

# gcc -g test.c -o test

# gdb test

image

命令按键
查看断点情况(gdb) info b
单步运行(gdb) n/(gdb) s
查看文件(gdb) l
设置断点(gdb) b 6
查看变量值(gdb) p n
运行代码(gdb) r
恢复程序运行(gdb) c
帮助(gdb) help [command]
退出(gdb) q

条件编译

编译器根据条件的真假决定是否编译相关的代码。

其语法如下:

  #ifdef  <macro>

     ……

  #else

     ……

  #endif

根据宏是否定义

image

image

定义:

image

根据宏的值

image

还有一种方式就是直接放数值0、1。

内存管理

C/C++定义了4个内存区间:

  • 代码区/全局变量与静态变量区/局部变量区即栈区/动态存储区,即区。

静态存储分配

  • 通常定义变量,编译器在编译时都可以根据该变量的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间。
  • 上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

动态存储分配

有些操作对象只有在程序运行时才能确定,这样编译器在编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为。

所有动态存储分配都在区中进行。

从堆上分配,亦称动态内存分配。程序在运行的时候用malloc申请任意多少的内存,程序员自己负责在何时用free释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

堆内存的分配与释放

当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象。当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配,做到重复使用有限的资源。

堆区是不会自动在分配时做初始化的(包括清零),所以必须用初始化式(initializer)来显式初始化。

malloc/free

void * malloc(size_t num):分配空间

void free(void *p):释放空间

  • malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。
  • malloc申请到的是一块连续的内存,有时可能会比所申请的空间大。其有时会申请不到内存,返回NULL。
  • malloc返回值的类型是void *,所以在调用malloc时要显式地进行类型转换,将void * 转换成所需要的指针类型。
  • 如果free的参数是NULL的话,没有任何效果。
  • 释放一块内存中的一部分是不被允许的。

image

注意事项

  • 删除一个指针p(free(p);),实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身,释放堆空间后,p成了空悬指针。
  • 动态分配失败。返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。
  • malloc与free是配对使用的, free只能释放堆空间。如果malloc返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,因为该空间可能已另分配,所以必须妥善保存malloc返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。

野指针

不是NULL指针,是指向“垃圾”内存的指针。“野指针”是很危险的。 “野指针”的成因主要有两种:

  • 指针变量没有被初始化。
  • 指针p被free之后,没有置为NULL,让人误以为p是个合法的指针。指针操作超越了变量的作用范围。这种情况让人防不胜防。

Makefile

Make简介

工程管理器,顾名思义,是指管理较多的文件。

Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它通过读入Makefile文件的内容来执行大量的编译工作。

Make将只编译改动的代码文件,而不用完全编译。

Makefile基本结构

Makefile是Make读入的唯一配置文件。

  • 由make工具创建的目标体(target),通常是目标文件或可执行文件。(生成什么)
  • 要创建的目标体所依赖的文件(dependency_file)(由谁生成)
  • 创建每个目标体时需要运行的命令(command)(怎么生成)

注意:命令行前面必须是一个“TAB键”,否则编译错误为:*** missing separator. Stop。

Makefile格式:

target  :   dependency_files

<TAB>  command

例子:

f1.c:

image

f2.c:

image

head.h:

image

main.c:

image

通过makefile生成一个目标代码文件:(.c->.o->obj)。

image

image

如果有一个文件和clean重命名,报make:'test' is up to date.的话,我们可以加一行语句,生成一个假目标,就可以继续执行了:

image

创建和使用变量

创建变量的目的:用来代替一个文本字符串:

  1. 系列文件的名字
  2. 传递给编译器的参数
  3. 需要运行的程序
  4. 需要查找源代码的目录
  5. 你需要输出信息的目录
  6. 你想做的其它事情。

变量定义的两种方式

  • 递归展开方式VAR=var

    它可以向后引用变量,但不能对该变量进行任何扩展,例如CFLAGS = $(CFLAGS) -O

  • 简单方式VAR:=var

    用这种方式定义的变量,会在变量的定义点,按照被引用的变量的当前值进行展开,这种定义变量的方式更适合在大的编程项目中使用,因为它更像我们一般的编程语言。

变量的使用:$(VAR)。如果想用"$“字符的话必须要用”$$"。变量名一般大写

image

用?=定义变量

dir := /foo/bar

FOO ?= bar

含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做,其等价于:

   ifeq ($(origin FOO), undefined)

      FOO = bar

   endif

为变量添加值

可以通过+=为已定义的变量添加新的值

Main=hello.o hello-1.o

Main+=hello-2.o

预定义变量

变量名作用
AR库文件维护程序的名称,默认值为ar。AS汇编程序的名称,默认值为as。
CCC编译器的名称,默认值为cc。CPP C预编译器的名称,默认值为$(CC) –E。
CXXC++编译器的名称,默认值为g++。
FCFORTRAN编译器的名称,默认值为f77
RM文件删除程序的名称,默认值为rm -f
ARFLAGS库文件维护程序的选项,无默认值。
ASFLAGS汇编程序的选项,无默认值。
CFLAGSC编译器的选项,无默认值。
CPPFLAGSC预编译的选项,无默认值。
CXXFLAGSC++编译器的选项,无默认值。
FFLAGSFORTRAN编译器的选项,无默认值。

自动变量

变量名作用
$*不包含扩展名的目标文件名称
$+所有的依赖文件,以空格分开,并以出现的先后为序,可能 包含重复的依赖文件
$<第一个依赖文件的名称
$?所有时间戳比目标文件晚的的依赖文件,并以空格分开
$@目标文件的完整名称
$^所有不重复的目标依赖文件,以空格分开
$%如果目标是归档成员,则该变量表示目标的归档成员名称

image

image

环境变量

  • make在启动时会自动读取系统当前已经定义了的环境变量,并且会创建与之具有相同名称和数值的变量
  • 如果用户在Makefile中定义了相同名称的变量,那么用户自定义变量将会覆盖同名的环境变量

Make使用

直接运行make。

选项

  • -C dir读入指定目录下的Makefile
  • -f file读入当前目录下的file文件作为Makefile
  • -i忽略所有的命令执行错误
  • -I dir指定被包含的Makefile所在目录
  • -n只打印要执行的命令,但不执行这些命令
  • -p显示make变量数据库和隐含规则
  • -s在执行命令时不显示命令
  • -w如果make在执行过程中改变目录,打印当前目录名

image

Makefile的隐含规则

隐含规则1:编译C程序的隐含规则

  • “.o”的目标的依赖目标会自动推导为“.c”,并且其生成命令是“ ( C C ) – c (CC) –c (CC)c(CPPFLAGS) $(CFLAGS)”

image

隐含规则2:链接Object文件的隐含规则

  • “” 目标依赖于“.o”,通过运行C的编译器来运行链接程序生成(一般是“ld”),其生成命令是:“ ( C C ) (CC) (CC)(LDFLAGS) .o ( L O A D L I B E S ) (LOADLIBES) (LOADLIBES)(LDLIBS)”。这个规则对于只有一个源文件的工程有效,同时也对多个Object文件(由不同的源文件生成)的也有效。例如如下规则:

x : x.o y.o z.o

并且“x.c”、“y.c”和“z.c”都存在时,隐含规则将执行如下命令:

cc -c x.c -o x.o

cc -c y.c -o y.o

cc -c z.c -o z.o

cc x.o y.o z.o -o x

如果没有一个源文件(如上例中的x.c)和你的目标名字(如上例中的x)相关联,那么,你最好写出自己的生成规则,不然,隐含规则会报错的。

比如:下面的test就会报错,而要用f1或者f2main

image

.c会自动生成.o,把三个.o生成target。

VPATH的用法

VPATH : 虚路径

在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make在自动去找。

Makefile文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。

VPATH = src:../headers

上面的的定义指定两个目录,“src”和“…/headers”,make会按照这个顺序进行搜索。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)

没用vpath:

image

用vpath:

image

Makefile的嵌套

下面是一个例子:

当前路径下的makefile文件:

image

当前目录下的所有文件和嵌套文件:

image

f1、f2、main下面的makefile文件内容:与下面类似。

image

这个执行过程就是当前下的makefile会把变量值export传给各个嵌套文件夹下的makefile文件。就可以实现嵌套了。

执行结果:

image

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

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

相关文章

《入门级-Cocos2d 4.0塔防游戏开发》---第二课:游戏加载界面开发

一、开发环境介绍 操作系统&#xff1a;UOS1060专业版本。 cocos2dx:版本 环境搭建教程&#xff1a; 统信UOS下配置安装cocos2dx开发环境_三雷科技的博客-CSDN博客 二、开发内容 游戏在开始时都需要加载大量的资源&#xff0c;为了让用户有等待时间&#xff0c;因此最先开…

linux学成之路(基础篇)(二十三)MySQL服务(数据库备份——补充)

目录 一、MySQL数据库备份 概述 重要性 造成数据丢失的原因 二、备份类型 一、物理与逻辑角度 一、物理备份 二、逻辑备份 二、数据库备份策略角度 一、完整备份 二、增量备份 三、常见的备份方法 一、物理备份 二、使用专用备份工具 三、通过启用二进制日志增量…

漏洞发现-Xray+Awvs联动-Goby+Xray+Awvs+Vulmap联动

Acunetix: Acunetix一款商业的Web漏洞扫描程序&#xff0c;它可以检查Web应用程序中的漏洞&#xff0c;如SQL注入、跨站脚本攻击、身份验证页上的弱口令长度等。它拥有一个操作方便的图形用户界面&#xff0c;并且能够创建专业级的Web站点安全审核报告。新版本集成了漏洞管理功…

在家构建您的迷你 ChatGPT

这篇文章分为三个部分&#xff1b;他们是&#xff1a; 什么是指令遵循模型&#xff1f;如何查找遵循模型的指令构建一个简单的聊天机器人废话不多说直接开始吧&#xff01;&#xff01;&#xff01; 什么是指令遵循模型&#xff1f; 语言模型是机器学习模型&#xff0c;可以根…

移动开发之Wifi列表获取功能

一、场景 业务需要通过App给设备配置无线网络连接&#xff0c;所以需要App获取附近的WiFi列表&#xff0c;并进行网络连接验证。 二、安卓端实现 1、阅读谷歌官网文档&#xff0c;关于Wifi 接口使用 https://developer.android.com/guide/topics/connectivity/wifi-scan?hl…

SpringBoot——内置数据库

简单介绍 关于数据层的三大组件&#xff0c;数据源&#xff0c;持久化技术&#xff0c;数据库。前两种都已经介绍过了SpringBoot的内置的解决方案&#xff0c;还有最后一个数据库&#xff0c;在SpringBoot中&#xff0c;内置了三款数据库。分别是&#xff1a; H2HSQLDerby 这…

ARTIF:一种先进的实时威胁智能识别框架

关于ARTIF ARTIF是一个新型的高级实时威胁智能框架&#xff0c;它基于MISP并添加了另一个抽象层&#xff0c;以实现根据IP地址和历史数据识别恶意Web流量。除此之外&#xff0c;该工具还可以通过收集、处理和关联基于不同因素的观测值来执行自动分析和威胁评分。 功能介绍 评…

uni-app在小米手机上运行【步骤细节】

注意细节重点&#xff1a; 1.手机使用数据线与电脑连接&#xff0c;手机连接模式必须是传输文件模式 2.手机必须打开开发者模式 3.打开开发者模式后&#xff0c;仔细浏览并调整USB调试权限&#xff0c;重点打开USB是否允许安装按钮&#xff01;&#xff01;&#xff01; 操作步…

onnxruntime (C++/CUDA) 编译安装

一、克隆及编译 git clone --recursive https://github.com/Microsoft/onnxruntime cd onnxruntime/ git checkout v1.8.0如果克隆的时候报错&#xff1a; 执行以下&#xff1a; apt-get install gnutls-bin git config --global http.sslVerify false git config --global h…

自动化测试的技术路线

本文中我谈一下自动化测试的技术路线&#xff0c;同时也是测试团队的发展路线。 团队路线1.工程化路线 如果你们公司只有你一个测试&#xff0c;那工程化的路线是必然的选择。另外&#xff0c;我个人比较推崇工程化而非平台化。 下图介绍了工程化路线下写出来的自动化测试&…

[oeasy]python0075_删除变量_del_delete_variable

删除变量 回忆上次内容 上次我们研究了字节序 字节序有两种 符号英文名称中文名称<little-endian小字节序>big-endian大字节序 字节序 用来 明确 整型数字存储的 顺序 如果 读写数字出了错 可以 考虑一下 是否 字节序出了问题 变量现在可以 声明初始化存储了 但是 …

Animator Animator Controller Avatar relationship

Animator 组件用于将动画分配给场景中的游戏对象。Animator 需要对Animator Controller 的引用&#xff0c;该控制器定义要使用的动画剪辑&#xff0c;并控制何时以及如何在它们之间混合和过渡。 如果 GameObject 是具有 Avatar 定义的人形角色&#xff0c;则 Avatar 也应在此组…

【数据结构】--189.轮转数组

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

Python GUI 案例 (tkinter module)

Python GUI 设计案例 基于matplotlib的 y-x 简单绘图 import tkinter as tk from tkinter import filedialog import matplotlib.pyplot as plt import numpy as npdef select_x_file():x_file_path filedialog.askopenfilename(title"x")x_file_entry.delete(0, t…

Pytorch学习笔记 | 数据类型 | mnist数据集

数据类型 python中数据类型和pytorch中的对应关系 注意:pytorch是没有没有string类型的 例1:创建一个3行4列的随机数数组,符合均值为0,方差为1的正态分布 import torch a=torch.Tensor(3,4) a Out[17]: tensor([[0.

iperf3跑满100G网卡实测记录

环境准备 拓扑 两台服务器 100G网卡对插直连。 ubuntu20.04, 系统设置默认状态 MTU 1500 网卡 Mellonax ConnectX5 100G rootvnet:~# lspci | grep Mellanox 98:00.0 Ethernet controller: Mellanox Technologies MT27800 Family [ConnectX-5] 98:00.1 Ethernet control…

【高级数据结构】树状数组

目录 树状数组1 &#xff08;单点修改&#xff0c;区间查询&#xff09; 树状数组1 &#xff08;单点修改&#xff0c;区间查询&#xff09; 洛谷&#xff1a;树状数组1https://www.luogu.com.cn/problem/P3374 题目描述 如题&#xff0c;已知一个数列&#xff0c;你需要进行…

汇报的目标和技巧【研发版】

汇报的组织意义 要做好汇报&#xff0c;需要先理解汇报的意义&#xff0c;这是根源上的指导。直接地说&#xff0c;满足上级的需求就是汇报的价值&#xff0c;而上级需求来自企业运作的需要&#xff0c;这也是各级管理者职责的组成部分。 各级管理者的职责&#xff08;倒序引用…

API声明文件Swagger Injection攻击

Swagger 在API化的世界里&#xff0c;相信无论是前端还是后端开发&#xff0c;都或多或少地被接口维护折磨过。随着API迭代&#xff0c;老旧API文档和SDK需要更新&#xff0c;这是一个耗散研发精力的事情。为解决此类问题&#xff0c;以API为软件能力最终交付物的生态不断演进…

实训笔记7.27

实训笔记7.27 7.27笔记一、Hive数据仓库基本概念&#xff08;处理结构化数据&#xff09;1.1 Hive的组成架构1.1.1 Hive的客户端1.1.2 Hive的驱动程序1.1.3 Hive的元数据库 1.2 Hive和数据库的区别 二、Hive的安装配置三、Hive的相关配置项四、Hive的基本使用方式4.1 使用Hive的…