Linux下的C编程实战(一)――开发平台搭建

简介:
Linux 下的 C 编程实战(一)

――开发平台搭建

1. 引言

       Linux 操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越 Windows 的安全性和稳定性。而近年来, Linux 操作系统在嵌入式系统领域的延伸也可谓是如日中天,许多版本的嵌入式 Linux 系统被开发出来,如 ucLinux RTLinux ARM-Linux 等等。在嵌入式操作系统方面, Linux 的地位是不容怀疑的,它开源、它包含 TCP/IP 协议栈、它易集成 GUI

        鉴于 Linux 操作系统在服务器和嵌入式系统领域愈来愈广泛的应用,社会上越来越需要基于 Linux 操作系统进行编程的开发人员。

浏览许多论坛,经常碰到这样的提问:“现在是不是很流行 unix/linux 下的 c 编程?所以想学习一下!但是不知道该从何学起,如何下手!有什么好的建议吗?各位高手!哪些书籍比较合适初学者?在深入浅出的过程中应该看哪些不同层次的书?比如好的网站、论坛请大家赐教!不慎感激!”

鉴于读者的需求,在本文中,笔者将对 Linux 平台下 C 编程的几个方面进行实例讲解,并力求回答读者们关心的问题,以与读者朋友们进行交流,共同提高。在本文的连载过程中,有任何问题或建议,您可以给笔者发送 email [email]21cnbao@21cn.com[/email] ,您也可以进入笔者的博客参与讨论: [url]http://blog.donews.com/21cnbao[/url]

笔者建议在 PC 内存足够大的情况下,不要直接安装 Linux 操作系统,最好把它安装在运行 VMWare 虚拟机软件的 Windows 平台上,如下图:

 
        Linux 平台下,可用任意一个文本编辑工具编辑源代码,但笔者建议使用 emacs 软件,它具备语法高亮、版本控制等附带功能,如下图:

 
2.GCC 编译器

       GCC Linux 平台下最重要的开发工具,它是 GNU C C++ 编译器,其基本用法为:

gcc [options] [filenames]

options 为编译选项, GCC 总共提供的编译选项超过 100 个,但只有少数几个会被频繁使用,我们仅对几个常用选项进行介绍。

假设我们编译一输出“ Hello World ”的程序:

/* Filename:helloworld.c */

main()

{

    printf("Hello World\n");

}

最简单的编译方法是不指定任何编译选项:

gcc helloworld.c

它会为目标程序生成默认的文件名 a.out ,我们可用 -o 编译选项来为将产生的可执行文件指定一个文件名来代替 a.out 。例如,将上述名为 helloworld.c C 程序编译为名叫 helloworld 的可执行文件,需要输入如下命令:

gcc –o helloworld helloworld.c

-c 选项告诉 GCC 仅把源代码编译为目标代码而跳过汇编和连接的步骤;

-S  编译选项告诉 GCC  在为  C 代码产生了汇编语言文件后停止编译。 GCC  产生的汇编语言文件的缺省扩展名是 .s ,上述程序运行如下命令:

gcc –S helloworld.c

将生成 helloworld.c 的汇编代码,使用的是 AT&T 汇编。用 emacs 打开汇编代码如下图:

 
 
-E 选项指示编译器仅对输入文件进行预处理。当这个选项被使用时,预处理器的输出被送到标准输出(默认为屏幕)而不是储存在文件里。

-O 选项告诉 GCC 对源代码进行基本优化从而使得程序执行地更快;而 -O2 选项告诉 GCC 产生尽可能小和尽可能快的代码。使用 -O2 选项编译的速度比使用 -O 时慢,但产生的代码执行速度会更快。

-g 选项告诉 GCC 产生能被 GNU 调试器使用的调试信息以便调试你的程序,可喜的是,在 GCC 里,我们能联用 -g -O ( 产生优化代码 )

-pg 选项告诉 GCC 在你的程序里加入额外的代码,执行时,产生 gprof 用的剖析信息以显示你的程序的耗时情况。

3.GDB 调试器

       GCC 用于编译程序,而 Linux 的另一个 GNU 工具 gdb 则用于调试程序。 gdb 是一个用来调试 C C++ 程序的强力调试器,我们能通过它进行一系列调试工作,包括设置断点、观查变量、单步等。

其最常用的命令如下:

file :装入想要调试的可执行文件。

kill :终止正在调试的程序。

list :列表显示源代码。

next :执行一行源代码但不进入函数内部。

step :执行一行源代码而且进入函数内部。

run :执行当前被调试的程序

quit :终止 gdb

watch :监视一个变量的值

break :在代码里设置断点,程序执行到这里时挂起

make :不退出 gdb 而重新产生可执行文件

shell :不离开 gdb 而执行 shell

下面我们来演示怎样用 GDB 来调试一个求 0+1+2+3+ +99 的程序:

/* Filename:sum.c */

main()

{

  int i, sum;

 

  sum = 0;

  for (i = 0; i < 100; i++)

  {

    sum +  = i;

  }

 

  printf("the sum of 1+2+...+ is %d", sum);

}

执行如下命令编译 sum.c (加 -g 选项产生 debug 信息):

gcc –g –o sum sum.c

在命令行上键入 gdb sum 并按回车键就可以开始调试 sum 了,再运行 run 命令执行 sum ,屏幕上将看到如下内容:

 
 
list 命令:

list 命令用于列出源代码,对上述程序两次运行 list ,将出现如下画面(源代码被标行号):

 
 
根据列出的源程序,如果我们将断点设置在第 5 行,只需在 gdb  命令行提示符下键入如下命令设置断点: (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 则不进入到函数内部,它把函数调用语句当作一条普通语句执行。

4.Make

make 是所有想在 Linux 系统上编程的用户必须掌握的工具,对于任何稍具规模的程序,我们都会使用到 make ,几乎可以说不使用 make 的程序不具备任何实用价值。

在此,我们有必要解释编译和连接的区别。编译器使用源码文件来产生某种形式的目标文件 (object files) ,在编译过程中,外部的符号参考并没有被解释或替换(即外部全局变量和函数并没有被找到)。因此,在编译阶段所报的错误一般都是语法错误。而连接器则用于连接目标文件和程序包,生成一个可执行程序。在连接阶段,一个目标文件中对别的文件中的符号的参考被解释,如果有符号不能找到,会报告连接错误。

编译和连接的一般步骤是:第一阶段把源文件一个一个的编译成目标文件,第二阶段把所有的目标文件加上需要的程序包连接成一个可执行文件。这样的过程很痛苦,我们需要使用大量的 gcc 命令。

make 则使我们从大量源文件的编译和连接工作中解放出来,综合为一步完成。 GNU Make 的主要工作是读进一个文本文件,称为 makefile 。这个文件记录了哪些文件(目的文件,目的文件不一定是最后的可执行程序,它可以是任何一种文件)由哪些文件(依靠文件)产生,用什么命令来产生。 Make 依靠此 makefile 中的信息检查磁盘上的文件,如果目的文件的创建或修改时间比它的一个依靠文件旧的话, make 就执行相应的命令,以便更新目的文件。

假设我们写下如下的三个文件, 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 "add.h"

main()

{

  int a, b;

  a = 2;

  b = 3;

  printf("the sum of a+b is %d", add(a + b));

}

怎样为上述三个文件产生 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 ,读者可以参阅相关资料。

5. 小结

本章主要阐述了 Linux 程序的编写、编译、调试方法及 make ,实际上就是引导读者学习怎样在 Linux 下编程,为后续章节做好准备。

 本文转自 21cnbao 51CTO博客,原文链接:http://blog.51cto.com/21cnbao/120047,如需转载请自行联系原作者




相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
2月前
|
Shell Linux
Linux shell编程学习笔记30:打造彩色的选项菜单
Linux shell编程学习笔记30:打造彩色的选项菜单
|
20天前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
1月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
82 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
2月前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
2月前
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
95 6
|
2月前
|
监控 Linux Shell
30 个实用的 Linux 命令贴与技巧,提升你的效率(附实战案例)
本文介绍了30个实用的Linux命令及其应用场景,帮助你提升命令行操作效率。涵盖返回目录、重新执行命令、查看磁盘使用情况、查找文件、进程管理、网络状态监控、定时任务设置等功能,适合各水平的Linux用户学习和参考。
|
2月前
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
140 3
|
2月前
|
存储 Linux 开发工具
如何进行Linux内核开发【ChatGPT】
如何进行Linux内核开发【ChatGPT】
|
2月前
|
Shell Linux Python
python执行linux系统命令的几种方法(python3经典编程案例)
文章介绍了多种使用Python执行Linux系统命令的方法,包括使用os模块的不同函数以及subprocess模块来调用shell命令并处理其输出。
35 0
|
3月前
|
Java Linux API
Linux设备驱动开发详解2
Linux设备驱动开发详解
43 6