浅谈嵌入式Linux下的C语言编程知识要点

电子说

1.3w人已加入

描述

基本开发环境

Linux和C语言有着很深的渊源,因为Linux本身就是用C语言编写的。同时,在Linux操作系统中也提供了C语言的开发环境。这些开发环境一般包括程序生成工具、程序调试工具、工程管理工具等。

  Linux下C语言开发环境

使用工具:程序生成工具GCC、程序调试工具GDB、工程管理工具为make和Makefile。

开发流程:使用编辑工具编写C语言源文件,然后编译生成机器代码为主的二进制可执行程序。

编译流程:C语言经过编译-汇编-链接,最终生成可执行程序格式。可执行程序包含两部分内容:程序头和程序主体。

程序的生成一般使用的是从x86到目标机的编译工具,程序的开发工具是运行于x86机器上的可执行程序,而是用开发工具生成的目标是以目标机器代码为实体的映像文件或者可执行程序,这个工程称为“交叉编译“。

和普通Linux环境下开发相比,更需要掌握一些几点:

库函数和系统调用

C语言高级应用

C语言在嵌入式中的特殊语法(大小端,内存对齐等)

资源性能考虑(运行效率与存储空间)

基本开发工具

文件编辑器vi

学习目标:

主要这个掌握VI三种模式的切换:命令模式、文本输入模式、和末行模式,以及VI编辑器的各种命令与操作。

学习VIM的使用,编辑vimrc文件,gedit ~./vimrc修改功能(比如显示行数、颜色加亮等)。

详细介绍:

vi是visual  editor的缩写,是UNIX提供给用户的一个窗口化编辑环境,在UNIX上被广泛使用的中英文编辑软件。进入vi,直接执行vi编辑程序即可。

例:vi  test.c或者 vim test.c。

显示器出现vi的编辑窗口,同时vi会将文件复制一份至缓冲区(buffer)。vi先对缓冲区的文件进行编辑,保留在磁盘中的文件则不变。编辑完成后,使用者可决定是否要取代原来旧有的文件。

vi提供三种工作模式:输入模式、命令模式和末行模式。

嵌入式

具体操作整理如下:

嵌入式

GCC程序开发工具

学习目标:

GCC能完成从C、C++、Objective-C等源文件向运行在特定CPU硬件上的目标代码的转换。对于通用计算机,一般使用GCC生成x86的可执行代码;对于嵌入式开发系统使用交叉编译的GCC,生成目标机可以运行的程序。

利用GCC/G++生成应用程序可以分为以下四步:

(1)预处理:生成.i文件(预处理器cpp)

(2)编译:将预处理后的文件转换为汇编语言,生成.s文件(编译器gcc)

(3)汇编:由汇编代码生成目标代码,即机器代码,生成.o文件(汇编器as)

(4) 链接:由各个文件的目标代码,生成可执行程序(链接器ld)

这里涉及到另外一个知识点就是静态链接库和动态链接库的生成。

详细介绍:

LINUX上可用的C编译器是GNU  C编译器,它建立在自由软件基金会编程许可证的基础上,因此可以自由发布。

LINUX 上的GNU  C编译器(GCC)是一个全功能的ANSI  C兼容编译器,而一般UNIX(如SCO UNIX)用的编译器是CC。下面介绍GCC和一些GCC编译器最常用的选项。

1.使用GCC

通常后跟一些选项和文件名来使用GCC编译器。GCC命令的基本用法如下:

gcc [options] [filenames]

命令行选项指定的编译过程中的具体操作

GCC有超过100个的编译选项可用,这些选项中的许多可能永远都不会用到,但一些主要的选项将会频繁使用。

当不用任何选项编译一个程序时,GCC将建立(假定编译成功)一个名为a.out的可执行文件。例如,

gcc  test.c

编译成功后,当前目录下就产生了一个a.out文件。

也可用-o选项来为即将产生的可执行文件指定一个文件名来代替a.out。例如:

gcc  –o count  count.c

此时得到的可执行文件就不再是a.out,而是count。

2.执行文件

格式: /可执行文件名

例: ./a.out

./count

Make工程管理工具

学习目标:

Makefile是一个决定怎样编译工程的文本文件,有一定的书写规则。在工程更新的时候,使用GNU的make工具根据当前的Makefile对工程进行有选择的编译。

自动生成Makefile的工具有autoconf、automake。其他的类似工具比如cMake等。

详细介绍:

1.make和Makefile的使用

make是一个Linux下的二进制程序,用来处理Makefile这种文本文件。在Linux的Shell 命令行键入make的时候,将自动寻找 名称为"Makefile"的文件作为编译文件,如果没有名称为"Makefile"的文件,将继续查找名称为"makefile"的文件。找到编译文件后,make工具将根据Makefile中的第一个目标自动寻找依赖关系,找出这个目标所需要的其他目标。如果所需要的目标也需要依赖其他的目标,make工具将一层层寻找直到找到最后一个目标为止。

make工具的使用格式为:

make[options] [target] ...

options为make工具的选项,target为Makefile中指定的目标。表5-1给出了make工具 的参数选项。

Make工具的参数选项如下表所示:

嵌入式

嵌入式

Makefile中常用变量如下表所示:

嵌入式

在Makefile中,目标名称的指定常常有以下惯例:

all:表示编译所有的内容,是执行make时默认的目标。

clean:表示清除目标。

distclean:表示清除所有的内容。

install:表示进行安装的内容

2.自动生成Makefile

在实际的项目中,由于 make规则的复杂性和不确定性,自己编写Makefile是一件费时费力的事情。Makefile本身具有一定的相似性,因此利用GNU autoconf及automake这两套工具可以协助我们自动产生 Makefile文件,并且让开发出来的软件可以像大多数源 代码包那样,只需运行命令"./configure"、 "make"、 "make install"就可以把程序安装到系 统中,对于各种源代码包的分发和兼容性具有很好的效果。

autoconf工具介绍

autoconf 是一个用于产生可以自动配置源代码包,生成Shell脚本的工具,它可以适应 各种类UNIX系统的需要。autoconf产生的配置脚本在运行时独立于autoconf,也就是说 使用这些脚本的用户不需要安装autoconf。

autoconf生成的配置脚本通常名称是configure,得到这个文件,通常需要以下的依赖文 件:

configure.in文件:生成configure的必需文件,需要手动编写。

aclocal.m4和acsite.m4文件:在编写了除autoconf提供的测试外的其他测试补充的时候, 才会用到这两个文件,也需要手动编写。

acconfig.h文件:如果使用了含有#define指令的头文件,则需要自行编写该文件,一般 都需要使用,这个时候会生成另外一个 config.h.in文件,这个文件需要和软件包一同发 布。

总之,在autoconf运行完毕后,得到两个需要和软件包同时发布的文件: configure和

config.h.in,当然config.h.in可以不存在。

automake工具介绍

automake是一个从文件Makefile.am自动生成Makefile.in的工具。每个Makefile.am基本 上是一系列 make的宏定义(make规则也会偶尔出现)。生成的 Makefile.in也服从GNU Makefile标准。

典型的 automake 输入文件是一系列简单的宏定义。处理所有相关的文件并创建 Makefile.in文件。在一个项目的每个目录中通常仅包含一个Makefile.am。

目前automake支持三种目录层次:平坦模式(flat)、混合模式(shallow)和深层模式 (deep)。

(1)平坦模式指的是所有文件都位于同一个目录中。就是所有源文件、头文件及其他库文件都位于当前目录中,且没有子目录。

(2)混合模式指的是主要的源代码都存储在顶层目录,其他各个部分则存储在子目录中。也就是主要源文件在当前目录中,而其他一些实现各部分功能的源文件位于各自不同的 目录。

(3)深层模式指的是所有源代码都被存储在子目录中;顶层目录主要包含配置信息。也就是所有源文件及程序员自己写的头文件都位于当前目录的一个子目录中,而当前目录 里没有任何源文件。

在这三种支持的目录层次中,平坦模式类型是最简单的,深层模式类型是最复杂的。但是 这些模式使用autoconf和automake所遵循的基本原则和流程是一样的。

其他工具介绍

(1)autoheader:能够产生供configure脚本使用的C #define语句模板文件。

(2)autom4te:对文件执行 GNU M4。

(3)autoreconf:如果有多个 autoconf产生的配置文件,autoreconf 可以保存一些相 似的工作,它通过重复运行 autoconf(以及在合适的地方运行 autoheader)以重新产生autoconf配置脚本和配置头模板,这些文件保存在以当前目录为根的目录树 中。

(4)autoscan:该程序可以用来为软件包创建configure.in文件。autoscan在以命令行 参数中指定的目录为根(如果未给定参数,则以当前目录为根)的目录树中检查源文件。 为软件包创建一个configure.scan文件,该文件就是configure.in的前身。

(5)autoupdate:该程序的作用是转换configure.in,从而使用新的宏名。

  GDB调试工具

学习目标:

在使用GDB之前,需要对源程序增加-g编译选项,此时编译出来的程序包含需要调试的信息,可以利用GDB进行调试。主要使用的命令是run(开始运行程序)、break(设置断点)、next(执行一行且不进入函数)、step(进入函数)、continue(继续程序运行)。

调试分为本地GDB调试和远程GDB调试,远程GDB更适合嵌入式系统的调试手段,使用个目标机端的GDB服务器和主机端的GDB调试器完成调试工作。

详细介绍:

LINUX包含了一个叫gdb的GNU调试程序。gdb是一个用来调试C和C++程序的强有力调试器。它使你能在程序运行时观察程序的内部结构和内存的使用情况。它具有以下一些功能:

• 监视程序中变量的值;

• 设置断点以使程序在指定的代码行上停止执行;

• 一行行的执行代码。

1.gdb基本命令

嵌入式

2.应用举例

(1)设有一源程序 greet.c

(2)编译,gcc  -ggdb –o greet  greet.c,出错

(3)gdb greet ,出现提示符

(gdb)

此时可在提示符下输入gdb的命令了,如:

(gdb) run

(gdb) list

(4)退出调试状态,返回系统提示符下,(gdb)quit

基本学习函数

C语言标准库函数

(1) 标准输入/输出类函数

scanf printf putchar getchar putc getc puts ungetc等。

(2) 字符处理及转换函数

isdigit isalpha sprint strncat stncpystrlen strchr strstr strrev memset memmove memcpy memcpy等。

(3) 数学计算类函数 

divacos/asin pow exp log ceil abs floor fmod等

(4) 数据结构和算法类函数

bsearch lfind lsearch qsort rand srand等

(5) 文件I/O操作类函数 

fopen fclose fgetc fputs fseek fwrite ffush等

(6) 时间日期类函数

clocktime gmttime mktime asctime 等

(7) 错误处理及工具函数

clearer feof perror errno assert setjmp longjmp等

Linux C中C语言的扩展库函数

(1) 文件I/O操作函数

open close read write lseek ioctl fcntl mmap dup create等

(2) 文件权限相关函数 

accesschown chmod utime umask link stat unlink等

(3) 用户操作函数

getgid/setgid getegid/setegid geteuid/seteuid 等

(4) 信号及进程类函数

killraise alarm signal getpid fork sleep exec _exit等

C语言高级编程

C语言运行过程中所使用的内存总体分为静态存储区和动态存储区两种。

静态存储区

C语言程序中静态数据存储区分为三类:只读存储器(RO)、已初始化读写数据区(RW Data)、未初始化读写存储器(BSS)。在程序运行初始化阶段开辟,在运行过程中不会变化(大小和位置固定),程序退出时被系统回收。

动态存储区

动态存储区分为堆和栈两类,在程序运行过程中动态分配(位置和大小动态变化),常见动态内存管理是栈内存从高地址向低地址分配,堆内存从低地址向高地址分配,一般来说堆使用链表实现,栈使用线性存储方式。

在C语言程序中,栈空间是由编译器管理的,在程序中可以体现栈空间使用的例子是参数的传递、返回值的使用以及自动变量空间。一般来说如果栈空间是从高地址向低地址增长的。

参数入栈的顺序是:后面的参数在高地址处、前面的参数在低地址处。

自动变量在栈空间,前面的变量放入栈的高地址,后面的自动变量放入栈的低地址。

在函数退出时函数栈上的内容将被释放。因此,自动变量的地址不可以作为函数返回值

在C语言中,堆内存区域的分配和释放是通过调用库函数完成的。

malloc、calloc、realloc、free4个库函数实现堆内存的分配、释放和管理。分配内存后要记得手动释放,否则其资源是不会被系统回收的,会造成内存泄漏。同时指针被释放后,指针应该被设置为NULL,避免野指针。

总的来说,栈内存是由编译器分配和释放,堆内存是由程序分配和释放。

函数指针的使用

函数指针是一个指向函数的指针(本质上是一个代码区的地址),而函数本身代表了算法,此时C语言的算法就可以通过指针的形式,像普通变量一样被使用。函数指针可以作为一个结构体的成员,也可也作为一个参数传递给其他的函数,同样也可以作为函数的返回值。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
圆滚滚的小肚子 2020-07-07
0 回复 举报
谢谢分享,非常不错 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分