前言
在数字天下的浩瀚星海中,Linux操作系统犹如一颗璀璨的恒星,以其开源、稳固和强盛的特性,照亮了无数开发者的编程之路。而C语言,作为最接近硬件层面的高级编程语言,以其无与伦比的性能和机动性,成为了构建Linux系统的基石。在这个布满挑战与机遇的期间,把握Linux情况下的C步伐设计,不仅是技能寻求,更是一种对极致性能和系统控制的渴望。
如今,让我们一起起程,深入Linux与C语言的神秘天下。
一、gcc编译系统
1.1 文件名后缀
目前Linux平台上最常用的C语言编译系统是gcc(GNU Compiler Collection)
常用文件名后缀及其表示的文件范例:
文件名后缀文件范例.cC源文件.i预处置处罚后的C源文件.ii预处置处罚后的C++源文件.hC或C++头文件.C .cc .cp .cpp .c++ .cxxC++源文件.s汇编步伐文件.S必须预处置处罚的汇编步伐文件.o目的文件.a静态链接库.so动态链接库 1.2 C语言编译过程
- 预处置处罚阶段预处置处罚步伐(Preprocessor)读取C语言源文件,对其中以“#”开头的指令(伪指令)和特殊符号进行处置处罚。 伪指令紧张包罗文件包罗、宏定义和条件编译指令。
- 编译阶段编译步伐(Compiler)对预处置处罚之后的输出文件进行词法分析和语法分析,试图找出所有不符合语法规则的部门。在确定各成分都符合语法规则后,将其“翻译”为功能等价的中间代码表示或者汇编代码。
- 汇编过程汇编步伐(Assembler)把汇编语言代码翻译成目的呆板代码的过程。
- 连接阶段将一个文件中引用的符号(如变量或函数调用)与该符号在另外一个文件中的定义连接起来,从而使有关的目的文件连成一个整体,终极成为可被操作系统执行的可执行文件。连接模式分为静态连接和动态连接。
1.3 gcc下令行选项
$ gcc f1.c f2.c (针对C语言源步伐) 执行完成后,天生默认的可执行文件a.out。
按照选项作用所对应的编译阶段,可将gcc的选项分为四组:预处置处罚选项、编译选项、优化选项和连接选项。
选项格式功能-C在预处置处罚后的输出中保留源文件中的注释-D name预定义一个宏name,而且其值为1-D name=definition预定义一个宏name,并指定其值为definition所指定的值。其作用等价于在源文件中利用宏定义指令:#define name definition。但-D选项比宏定义指令的优先级高,它可以覆盖源文件中的定义-U name取消先前对name的任何定义,不管是内置的,还是由-D选项提供的-I dir指定搜索头文件的路径dir。先在指定的路径中搜索要包罗的头文件,若找不到,则在标准路径(/usr/include, /usr/lib及当前工作目录)上搜索-E只对指定的源文件进行预处置处罚,不做编译,天生的结果送到标准输出 例:
- # 添加“-I /root”参数编译,/root为my.h文件位置
- gcc 1-3.c -o 1-3 -I /root
复制代码 选项格式功能-c只天生目的文件,不进行连接。用于对源文件的分别编译-S只进行编译,不做汇编,天生汇编代码文件格式,其名与源文件雷同,但扩展名为.s-o file将输出放在文件file中。如果未利用该选项,则可执行文件放在a.out中-g指示编译步伐在目的代码中参加供调试步伐gdb利用的附加信息-v在标准堕落输出上显示编译阶段所执行的下令,即编译驱动步伐及预处置处罚步伐的版本号 优化分为对中间代码的优化和针对目的代码天生的优化。
选项格式功能object -file -name不以专用后缀结尾的文件名就认为是目的文件名或库名。连接步伐可以根据文件内容来区分目的文件和库-c -S -E如果利用其中任何一个选项,那么都不运行连接步伐,而且目的文件名不应该用做参数-llibrary连接时搜索由library命名的库。连接步伐按照在下令行上给定的次序搜索和处置处罚库及目的文件。实际的库名是liblibrary.a-static在支持动态连接的系统中,它欺压利用静态链接库,而阻止连接动态库;而在其他系统中不起作用-Ldir把指定的目录dir加到连接步伐搜索库文件的路径表中,即在搜索-l背面列举的库文件时,首先到dir下搜索,找不到再到标准位置下搜索-Bprefix该选项规定在什么地方查找可执行文件、库文件、包罗文件和编译步伐自己数据文件-o file指定连接步伐最后天生的可执行文件名称为file,不是默认的a.out
- Linux下库文件的命名有一个约定,所有的库名都以lib开头。因此,在-l选项所指定的文件名前主动地插入lib。并且约定,以.a(归档,archive)结尾的库是静态库,以**.so(共享目的,shared object)结尾的库是动态库**。
- 天生静态库的方法实际上可分为两步:
① 将各函数的源文件编译成目的文件。例如:
\$ gcc -c f1.c f2.c f3.c -o game.o
由此可得到各源文件的目的文件game.o。
② 利用ar工具将目的文件收集起来,放到一个归档文件中。例如:
\$ ar -rcs \$HOME/lib/libgame.a game.o
- 天生静态库以后,就可在编译C语言源文件时指明对它进行搜索、连接,例如:
\$ gcc f1.c f2.c f3.c -o mygame -static -L$HOME/lib -lgame
例:
gcc编译静态库
- #gcc 编译静态库并调用,演示如何将 add.c 打包成一个静态库来供 main.c 调用.
- #1.首先将add.c编译成目标文件。
- gcc -c add.c -o add.o
- # 2.ar 打包静态库,将 add.o 打包成 libadd.a,
- #参数 [-crv] :–c表示建立备存文件,- r表示将文件插入备存文件中,-v表示程序执行时显示详细的信息
- ar -crv libadd.a add.o
- #3.使用静态库 libadd.a编译main.c, [-L./] 表示将当前目录加到静态库的搜索路径
- gcc main.c -L./ libadd.a -o main2
- #4.执行
- ./main2
复制代码 gcc 编译动态库
- #1.编译位置无关的目标文件 add.o,因为动态库动态加载到内存中的位置不确定,所以需要编译位置无关
- gcc -fPIC -c add.c -o add.o
- 打包成动态库,
- #2.如果不加 sudo 会提示没有权限,如果不指定/usr/lib/文件夹,会在执行时提示
- #error while loading shared libraries:libadd.so: cannot open shared object file: No such file or directory
- sudo gcc -shared add.o -o /usr/lib/libadd.so
- #3.编译
- sudo gcc -0 main3 main.c -L /usr/lib/ -ladd
- #4.执行
- ./main3
复制代码 二、gdb步伐调试工具
步伐中的错误按其性质可分为三种:
(1)编译错误,即语法错误。紧张是步伐代码中有不符合所用编程语言语法规则的错误。
(2)运行错误。如对负数开平方,除数为0,循环终止条件永世不能到达等 。
(3)逻辑错误。这类错误每每是编程前对求解的问题理解不正确或算法不正确引起的,它们很难查找。查找步伐中的错误,诊断其正确位置,并予以改正,这就是步伐调试。步伐调试分为人工查错与呆板调试。
gdb紧张帮助用户在调试步伐时完成四方面的工作:
(1)启动步伐,可以按用户要求影响步伐的运行行为。
(2)使运行步伐在指定条件处制止。
(3)当步伐制止时,检查它出现了什么问题。
(4)动态改变步伐的执行情况,这样就可以改正一个错误的影响,然后再改正其他错误。
2.1 启动gdb和检察内部下令
为了发挥gdb的全部功能,必要在编译源步伐时利用-g选项:
- gcc -g prog.c -o prog #(针对C语言源程序prog.c)
- gcc -g program.cpp -o program # (针对C++源程序program.cpp)
复制代码 启动gdb的常用方法有:
(1)以一个可执行步伐作为gdb的参数:
$ gdb prgm
(2)同时以可执行步伐和core文件作为gdb的参数:
$ gdb prgm core
启动gdb后就显示其提示符:(gdb),并等待用户输入相应的内部下令。
用户可以利用下令quit终止其执行,退出gdb情况。
2.2 显示源步伐和数据
2.2.1 显示和搜索源步伐
(1)显示源文件
利用list下令可以显示源文件中指定的函数或代码行。
格式功能list没有参数,显示当前行之后或周围的10多行list –显示先前10行之前的10行list [file:] num显示源文件file中给定行号num周围的10行。如果缺少file,则默认为当前文件。例如,list 100list start , end显示从行号start至end之间的代码行。例如,list 20,38list [file:]function显示源文件file中指定函数function的代码行。如果缺少file,则默认为当前文件。例如,list meng1.c:square 也可以利用set listsize下令重新设置一次显示源步伐的行数:
set listsize linenum
(2)模式搜索
格式功能forward-search regexp从列出的最后一行开始向前搜索给定的模式regexp(即正则表达式,一个字符串的匹配模式)。例如,forward-search i=*search regexp同上reverse-search regexp从列出的最后一行开始向后搜索给定的模式regexp(即正则表达式,一个字符串的匹配模式)。例如,reverse-search i=?? 2.2.2 检察运行时数据
(1)print下令
- 当被调试的步伐制止时,可以用print下令(简写为p)或同义下令inspect来检察当前步伐中运行的数据。
- print下令的一样平常利用格式:print [/fmt] exp
print i (或p i) 显示当前变量i的值。
print i\*j (或p i\*j) 将根据步伐当前运行的实际情况显示出i*j的值。
(2)gdb所支持的运算符
①用&运算符取出变量在内存中的地点,如:
print &i 显示变量i的存放地点。
print &array 显示数组array第i个元素的地点。
② { type }adrexp 表示一个数据范例为type、存放地点为adrexp的数据。
③ @ 是一个与数组有关的双目运算符,利用形式如:
print array@10 打印从array(数组名,即数组的基地点)开始的10个值。
print array[3]@5 打印从array第三个元素开始的5个数组元素的数值。
④file :: var (或者 function :: var ) 表示文件file(或者函数function)中变量var的值。例如:
print inner::i 打印函数inner中变量i的当前值。
(3)输特殊式
由表示格式的字母(如o、x、d、u、t、f、a、i、c、s)和表示数据长度的字母(如b、w、h、g)组成。
2.3 改变和显示目录或路径
(1)directory下令
将给定目录dir添加到源文件搜索路径的开头,并且忽略先前生存的有关源文件和代码行位置的信息。其一样平常格式是:
directory [dir] 或者 dir [dir]
(2)cd下令
cd下令将调试步伐和被调试步伐的工作目录置为指定的目录dir。其利用格式为:
cd dir
(3)path下令
利用path下令可以将一个或多个目录添加到目的文件搜索路径的开头。其利用格式是:
path dirs
(4)pwd下令
该下令用来显示工作目录。
(5)show directories下令
该下令显示定义的源文件搜索路径。
(6)show paths下令
该下令显示当前查找目的文件的搜索路径。
2.4 控制步伐的执行
2.4.1 设置断点
编译源步伐时必要利用-g选项
在gdb中用break下令(其缩写形式为b)设置断点:
● break linenum (在当前文件指定行linenum处设置断点,停在该行开头)
● break linenum if condition (在当前文件指定行linenum处设置断点,但仅在条件表达式condition成立时才制止步伐执行)
● break function (在当前文件函数function的入口处设置断点)
● break file:linenum (在源文件file的linenum行上设置断点)
● break file:function (在源文件file的函数function的入口处设置断点)
● break *address (运行步伐在指定的内存地点address处制止)
● break (不带任何参数,则表示在下一条指令处制止)
断点应设置在可执行的行上,不应是变量定义之类的语句。
2.4.2 显示断点
- info breakpoints [num]
- info break [num]
复制代码 2.4.3 删除断点
delete [bkptnums]
2.4.4 运行步伐
run [args] (run简写是r)
2.4.5 步伐的单步跟踪和一连执行
(1)单步跟踪
step [N] 参数N表示每步执行的语句行数。 进入被调用函数内部执行。
next [N] 参数N表示每步执行的语句行数。 被调用函数被当做一条指令执行。
stepi(缩写为si)或nexti(缩写为ni)下令一条一条地执行呆板指令。
(2)一连执行
利用continue,c或fg下令一连执行到下一个断点
2.4.6 函数调用
call expr
其中,expr是所用编程语言的函数调用表达式,包罗函数名和实参。
- 在调试过程中,可以利用return下令强行从正在执行的函数中退出:
return [expr]
- 还可以利用finish下令退出函数,但它并不立刻退出,而是继续运行,直至当前函数返回
2.5 其他常用下令
1.执行shell下令
shell command-string
例如:
(gdb) shell date
2009年 03月 31日 星期二 16:47:56 CST
(gdb)
2.修改变量值
(gdb) print x=10
(gdb) set variable x=10
3.跳转执行
jump linenum (参数linenum表示下一条语句的行号。)
jump *addr (参数 addr表示下一条代码行的内存地点。)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |