主要内容:
1 :文本编辑器
2:Gcc 编译器的使用
3:GDB debug调试器
4:make
一:文本编辑器
在Linux平台下,可用任意一个文本编辑工具编辑源代码,但笔者建议使用emacs软件,它具备语法高亮、版本控制等附带功能
二:GCC编译器
GCC 是 GNU 编译器集合(GNU Compiler Collection)的首字母缩写词。它可以编译 C,C++,Objective-C,Fortran,Java 和 Ada 语言。
GCC是Linux平台下最重要的开发工具,它是GNU的C和C++编译器,其基本用法为:
gcc [options] [filenames]
options为编译选项,GCC总共提供的编译选项超过100个,但只有少数几个会被频繁使用,我们仅对几个常用选项进行介绍。
提示:编译选项是区分大小写的,一定要注意
假设我们编译一输出“Hello World”的程序:
/* Filename:helloworld.c */
#include <stdio.h>
int main()
{
int i=0;
printf("helloword!\n");
return 0;
}
最简单的编译方法是不指定任何编译选项:
gcc helloworld.c
它会为目标程序生成默认的文件名a.out,我们可用-o编译选项来为将产生的可执行文件指定一个文件名来代替a.out。例如,将上述名为helloworld.c的C程序编译为名叫helloworld的可执行文件,需要输入如下命令:
gcc –o helloworld helloworld.c
-Wall 开启编译器几乎所有常用的警告──强烈建议你始终使用该选项。
-c选项告诉GCC仅把源代码编译为目标代码而跳过汇编和连接的步骤;
-S (大写)编译选项告诉GCC 在为 C代码产生了汇编语言文件后停止编译。GCC 产生的汇编语言文件的缺省扩展名是.s,上述程序运行如下命令:
gcc –S helloworld.c
将生成helloworld.c的汇编代码,使用的是AT&T汇编。
-E选项指示编译器仅对输入文件进行预处理。当这个选项被使用时,预处理器的输出被送到标准输出(默认为屏幕)而不是储存在文件里。
-O选项告诉GCC对源代码进行基本优化从而使得程序执行地更快;而-O2选项告诉GCC产生尽可能小和尽可能快的代码。使用-O2选项编译的速度比使用-O时慢,但产生的代码执行速度会更快。
-g选项告诉GCC产生能被GNU调试器使用的调试信息以便调试你的程序,可喜的是,在GCC里,我们能联用-g和-O (产生优化代码)。
-pg选项告诉GCC在你的程序里加入额外的代码,执行时,产生gprof用的剖析信息以显示你的程序的耗时情况。
☆要运行该程序,输入可执行文件的路径如下:
代码:
$ ./hello
helloword!
这将可执行文件载入内存,并使 CPU 开始执行其包含的指令。
路径 ./ 指代当前目录,
因此 ./hello 载入并执行当前目录下的可执行文件 ‘hello’。
三:GDB debug调试器
GCC用于编译程序,而Linux的另一个GNU工具gdb则用于调试程序。gdb是一个用来调试C和C++程序的强力调试器,我们能通过它进行一系列调试工作,包括设置断点、观查变量、单步等。
其最常用的命令如下:
list:列表显示源代码。
run:执行当前被调试的程序
kill:终止正在调试的程序。
quit:终止gdb
file:装入想要调试的可执行文件。
break:在代码里设置断点,程序执行到这里时挂起
next:执行一行源代码但不进入函数内部。
step:执行一行源代码而且进入函数内部。
watch:监视一个变量的值
make:不退出gdb而重新产生可执行文件
shell:不离开gdb而执行shell
小提示:输入命令可以只输入头字母代替 如 l -> list
下面我们来演示怎样用GDB来调试一个求0+1+2+3+…+99的程序:
/* Filename:sum.c */
#include <stdio.h>
int main()
{
int i, sum;
sum = 0;
for (i = 0; i < 100; i++){
sum += i;
}
printf("the sum of 1+2+...+99 = %d", sum);
return 0;
}
执行如下命令编译sum.c(加-g选项产生debug信息):
gcc –g –o sum sum.c
在命令行上键入gdb sum并按回车键就可以开始调试sum了,再运行run命令执行sum,屏幕上将看到如下内容:
list命令:
list命令用于列出源代码,带行号。
break命令设置断点
break <lineNum>
break <function>,
①行断点:根据列出的源程序,如果我们将断点设置在第5行,只需在gdb 命令行提示符下键入break 5命令设置断点
(gdb) break 5
这个时候我们再run,程序会停止在第5行,
②函数入口断点 break <function>,它在进入指定函数(function)时停住。
相反的,clear用于清除所有的已定义的断点,clear <function>清除设置在函数上的断点, clear <linenum>则清除设置在指定行上的断点。
watch命令:
watch命令用于观查变量或表达式的值,在单步执行是显示。
我们观查sum变量只需要运行watch sum:
watch <expr>为表达式(变量)expr设置一个观察点,一量表达式值有变化时,程序会停止执行。
要观查当前设置的watch,可以使用info watchpoints命令。
next、step命令:
next、step用于单步执行,在执行的过程中,被watch变量的变化情况将实时呈现(分别显示Old value和New value),
next、step命令的区别在于step遇到函数调用,会跳转到到该函数定义的开始行去执行,而next则不进入到函数内部,它把函数调用语句当作一条普通语句执行。
四:Make
make是所有想在Linux系统上编程的用户必须掌握的工具,对于任何稍具规模的程序,我们都会使用到make,几乎可以说不使用make的程序不具备任何实用价值。
在此,我们有必要解释编译和连接的区别。编译器使用源码文件来产生某种形式的目标文件(object files),在编译过程中,外部的符号参考并没有被解释或替换(即外部全局变量和函数并没有被找到)。因此,在编译阶段所报的错误一般都是语法错误。而连接器则用于连接目标文件和程序包,生成一个可执行程序。在连接阶段,一个目标文件中对别的文件中的符号的参考被解释,如果有符号不能找到,会报告连接错误。
编译和连接的一般步骤是:第一阶段把源文件一个一个的编译成目标文件,第二阶段把所有的目标文件加上需要的程序包连接成一个可执行文件。这样的过程很痛苦,我们需要使用大量的gcc命令。
而make则使我们从大量源文件的编译和连接工作中解放出来,综合为一步完成。GNU Make的主要工作是读进一个文本文件,称为makefile。这个文件记录了哪些文件(目的文件,目的文件不一定是最后的可执行程序,它可以是任何一种文件)由哪些文件(依靠文件)产生,用什么命令来产生。Make依靠此makefile中的信息检查磁盘上的文件,如果目的文件的创建或修改时间比它的一个依靠文件旧的话,make就执行相应的命令,以便更新目的文件。
Make 从 makefile(默认是当前目录下的名为‘Makefile’的文件)中读取项目的描述。makefile指定了一系列目标(比如可执行文件)和依赖(比如对象文件和源文件)的编译规则,其格式如下:
目标: 依赖
命令
对每一个目标,make 检查其对应的依赖文件修改时间来确定该目标是否需要利用对应的命令重新建立。注意到,makefile 中命令行必须以单个的 TAB 字符进行缩进,不能是空格。
GNU Make 包含许多默认的规则(参考隐含规则)来简化 makefile 的构建。比如说,它们指定‘.o’文件可以通过编译‘.c’文件得到,可执行文件可以通过将‘.o’链接到一起获得。隐含规则通过被叫做make变量的东西所指定,比如 CC(C 语言编译器)和 CFLAGS(C程序的编译选项);在makefile文件中它们通过独占一行的 变量=值 的形式被设置。对 C++ ,其等价的变量是CXX和CXXFLAGS,而变量CPPFLAGS则是编译预处理选项。
假设我们写下如下的三个文件,add.h用于声明add函数,add.c提供两个整数相加的函数体,而main.c中调用add函数:
/* filename:add.h */
extern int add(int i, int j);
/* filename:add.c */
int add(int i, int j)
{
return i + j;
}
/* filename:main.c */
#include <stdio.h>
#include "add.h"
int main()
{
int a, b;
a = 2;
b = 3;
printf("the sum of a+b is %d \n", add(a , b));
return 0;
}
怎样为上述三个文件产生makefile呢?如下:
test : main.o add.o
gcc main.o add.o -o test
main.o : main.c add.h
gcc -c main.c -o main.o
add.o : add.c add.h
gcc -c add.c -o add.o
上述makefile利用add.c和add.h文件执行gcc -c add.c -o add.o命令产生add.o目标代码,利用main.c和add.h文件执行gcc -c main.c -o main.o命令产生main.o目标代码,最后利用main.o和add.o文件(两个模块的目标代码)执行gcc main.o add.o -o test命令产生可执行文件test。
我们可在makefile中加入变量,另外。环境变量在make过程中也被解释成make的变量。这些变量是大小写敏感的,一般使用大写字母。Make变量可以做很多事情,例如:
i) 存储一个文件名列表;
ii) 存储可执行文件名;
iii) 存储编译器选项。
要定义一个变量,只需要在一行的开始写下这个变量的名字,后面跟一个=号,再跟变量的值。引用变量的方法是写一个$符号,后面跟(变量名)。我们把前面的 makefile 利用变量重写一遍(并假设使用-Wall -O –g编译选项):
OBJS = main.o add.o
CC = gcc
CFLAGS = -Wall -O -g
test : $(OBJS)
$(CC) $(OBJS) -o test
main.o : main.c add.h
$(CC) $(CFLAGS) -c main.c -o main.o
add.o : add.c add.h
$(CC) $(CFLAGS) -c add.c -o add.o
makefile 中还可定义清除(clean)目标,可用来清除编译过程中产生的中间文件,例如在上述makefile文件中添加下列代码:
clean:
rm -f *.o
运行make clean时,将执行rm -f *.o命令,删除所有编译过程中产生的中间文件。
不管怎么说,自己动手编写makefile仍然是很复杂和烦琐的,而且很容易出错。因此,GNU也为我们提供了Automake和Autoconf来辅助快速自动产生makefile,读者可以参阅相关资料。
五:链接外部库
库是预编译的目标文件(object files)的集合,它们可被链接进程序。静态库以后缀为‘.a’的特殊的存档文件(archive file)存储。
标准系统库可在目录 /usr/lib 与 /lib 中找到。比如,在类 Unix 系统中 C 语言的数学库一般存储为文件 /usr/lib/libm.a。该库中函数的原型声明在头文件 /usr/include/math.h 中。C 标准库本身存储为 /usr/lib/libc.a,它包含 ANSI/ISO C 标准指定的函数,比如‘printf’。对每一个 C 程序来说,libc.a 都默认被链接。
下面的是一个调用数学库 libm.a 中 sin 函数的的例子,创建文件calc.c:
#include <math.h>
#include <stdio.h>
int main (void)
{
double x = sin (2.0);
printf ("The value of sin(2.0) is %f\n", x);
return 0;
}
尝试单独从该文件生成一个可执行文件将导致一个链接阶段的错误:
$ gcc -Wall calc.c -o calc
/tmp/ccbR6Ojm.o: In function 'main':
/tmp/ccbR6Ojm.o(.text+0x19): undefined reference to ‘sin’
函数 sin,未在本程序中定义也不在默认库‘libc.a’中;除非被指定,编译器也不会链接‘libm.a’。
为使编译器能将 sin 链接进主程序‘calc.c’,我们需要提供数学库‘libm.a’。一个容易想到但比较麻烦的做法是在命令行中显式地指定它:
$ gcc -Wall calc.c /usr/lib/libm.a -o calc
函数库‘libm.a’包含所有数学函数的目标文件,比如sin,cos,exp,log及sqrt。链接器将搜索所有文件来找到包含 sin 的目标文件。
一旦包含 sin 的目标文件被找到,主程序就能被链接,一个完整的可执行文件就可生成了:
$ ./calc
The value of sin(2.0) is 0.909297
可执行文件包含主程序的机器码以及函数库‘libm.a’中 sin 对应的机器码。
为避免在命令行中指定长长的路径,编译器为链接函数库提供了快捷的选项‘-l’。例如,下面的命令
$ gcc -Wall calc.c -lm -o calc
与我们上面指定库全路径‘/usr/lib/libm.a’的命令等价。
一般来说,选项 -lNAME使链接器尝试链接系统库目录中的函数库文件 libNAME.a。一个大型的程序通常要使用很多 -l 选项来指定要链接的数学库,图形库,网络库等。
分享到:
相关推荐
在Linux环境下进行C编程,首先需要搭建一个开发平台。这个过程包括选择合适的Linux发行版,安装必要的开发工具,以及熟悉常用的开发工具和命令。Linux操作系统以其开源、稳定和安全性在服务器和嵌入式系统领域广泛...
从给定的文件信息来看,核心关注点在于“Linux.C编程实战.pdf”,这是一份关于在Linux环境下进行C语言编程的实战指南。虽然文件描述部分包含了大量的广告信息和社区介绍,但我们的重点将放在与标题和描述相关的知识...
本书详细介绍了在Linux环境下进行C语言编程的全过程,包括开发环境搭建、程序编译、调试等关键环节,为读者提供了一条清晰的Linux C编程学习路径。 首先,作者在书中指出,Linux在当前的软件开发领域中扮演着关键...
### Linux C编程实战:开发平台搭建与编程技巧详解 #### 开发平台搭建 在Linux操作系统中,C语言编程因其高效性、灵活性以及广泛的系统级控制能力而受到开发者的青睐。对于初学者而言,搭建一个合适的开发环境至关...
### Linux下的C编程实战知识点详解 #### 一、开发平台搭建 在开始具体的编程实践之前,首先需要构建一个合适的开发环境。根据文章描述,这里主要介绍如何在Linux环境下搭建C编程开发平台。 - **选择合适的Linux...
首先,搭建开发平台是学习Linux下C编程的第一步。通常,建议在具有足够内存的PC上安装Linux操作系统,如Ubuntu或Fedora,以避免对现有Windows系统的影响。然而,对于初学者或希望多系统共存的情况,可以使用虚拟机...
《Linux C编程实战》这本书是针对想要在Linux环境下进行C语言编程的读者而设计的实践指南。它涵盖了从基础知识到高级特性的全方位讲解,旨在帮助读者深入理解和掌握C语言在Linux系统中的应用。 Linux是一种开源操作...
通过上述知识点的介绍,我们可以看到,在Linux环境下进行C语言编程不仅需要掌握基本的编程技巧,还需要熟悉开发环境的搭建、编译器的使用以及调试工具的操作。这对于初学者来说可能是一项挑战,但随着实践的不断深入...
根据提供的信息,“Linux下的C编程”是一本介绍在Linux环境下进行C语言编程的书籍。它主要面向初学者,旨在提供一个全面且易于理解的学习指南。接下来,我们将详细探讨与该书相关的几个关键知识点: ### 1. Linux...
"Linux环境C程序设计"是针对C语言在Linux环境下的编程实践,包括标准库函数的使用、系统调用、多线程编程、文件I/O等。 "Linux命令、编辑器与Shell编程"着重于提高用户在命令行的效率,如熟练使用vi/vim编辑器,...
总之,《Linux C一站式编程》是一本全面介绍Linux下C语言编程的书籍,适合想要在Linux环境中开发C程序的初学者,通过学习,读者将能够熟练掌握C语言编程技巧,并具备在Linux系统上进行软件开发的能力。
在“Linux_C编程一站式学习”这个资源中,你将获得深入理解Linux系统和C语言编程的宝贵知识。C语言是计算机科学的基础,尤其在操作系统开发和低级别编程中至关重要,而Linux作为开源的操作系统,为开发者提供了丰富...
通过以上内容的详细介绍可以看出,《高级Linux编程》这本书覆盖了从基础到高级的所有Linux编程技术,并且结合了大量的实战案例和实践经验分享,非常适合想要深入了解Linux环境下的高级编程技术的开发者阅读。
这个资源包包含了一个名为"基于嵌入式 Linux 的 Qt图形实战开发 PDF"的文档,以及与之相关的C和C++源码,为学习和实践Qt在嵌入式环境中的应用提供了全面的指导。 首先,Qt框架的核心是其C++库,它包含了大量预定义...
3. **C语言编程**:作为嵌入式开发的基础,C语言的重要性不言而喻。书中会深入解析C语言的关键特性,如指针、结构体、文件操作等,并结合嵌入式应用给出实例。 4. **Linux内核与驱动开发**:讲解如何与硬件交互,...
进入编程环节,Linux支持多种编程语言,如C、C++、Python、Java等。对于C和C++,理解它们的语法基础,学会使用gcc/g++编译器,以及如何进行动态和静态链接。Python则以其简洁的语法和丰富的库资源受到欢迎,学习...
3. **嵌入式Linux应用程序开发**:介绍如何在嵌入式平台上开发应用程序,包括图形用户界面(GUI)的实现,以及网络编程和多线程编程技术。 4. **嵌入式Linux项目实践**:提供实际的案例分析和项目实践,帮助读者巩固...