嵌入式开发第1站——突破C++(txt+pdf+epub+mobi电子书下载)


发布时间:2020-05-16 02:30:29

点击下载

作者:周建设

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

嵌入式开发第1站——突破C++

嵌入式开发第1站——突破C++试读:

前言

本书的编写目的

随着嵌入式硬件技术的不断更新换代,对于嵌入式软件的开发,单纯地使用汇编语言、C语言已经很难满足大型项目的开发需求。目前C++语言已经成为嵌入式应用层开发最流行的编程语言之一,本书不求讲到每一个C++语言的知识点,重点讲解实际项目中常用的一些知识点、开发技术,并且重点分析当前刚入行的软件工程师比较模糊的问题,分析容易犯错的地方,从而提高他们实际的开发技能。

本书的特色

本书是C++语言开发从入门到提高的教材,通过理论结合实际的方式,深入浅出地介绍其使用方法和技巧。目的在于让读者快速提高C++语言的开发技能。本书在编写过程中力求精益求精、浅显易懂、理论结合实际,通过实用性较强的实例展示C++语言相关知识点在实际产品开发中的应用。如果读者能够遵循相关的编程规范,掌握关键细节的使用技巧和常见错误的排查思路,再加上一定代码的编程训练,那么就能很快提高实际的开发技能。

本书对重要的知识点采用“加油站”的方式进行讲解,剖析相关技术的内部细节,让读者明白相关技术理论背后的内幕,并且对产品开发中的常用知识点在“训练场”中进行实战训练,在此过程中结合一些常犯的错误细节进行剖析,并及时做出点评与总结。

本书的主要组成部分

本书由11章组成,分为三大部分。第一部分是第1章至第2章,介绍嵌入式开发背景知识,C++语言开发的基础知识,涉及C++语言的基本概念,常用开发技巧等。第二部分是第3章至第9章,介绍C++语言面向对象编程的核心技术,这是本书的重点,涉及对类、对象等概念的剖析,重点讨论面向对象的三大特征(封装、继承与多态)在实际产品开发的应用。第三部分是第10章至第11章,介绍C++语言编程的高级知识:模板的用法,涉及自定义模板和标准模板库(STL)的使用。每章内容的概要如下所述。

● 第 1 章 嵌入式开发初体验。本章介绍什么是嵌入式系统,嵌入式系统的体系结构,主流嵌入式系统简介,为什么选择C++,C++编译环境介绍等。

● 第2章 嵌入式C++开发必备知识。本章的知识点较多,概括起来主要包括C++程序结构、变量与常量、基本数据类型、C++基础语句、操作符与表达式、指针、数组、结构体、位段、联合、函数、引用以及数据类型强制转换的方法等内容。本章知识点的介绍侧重点在实际应用,而不是仅仅对纯概念的诠释,为让读者更直观地理解相关复杂的概念,本章结合了近百个实例进行辅助讲解。

● 第 3 章 C++标准输入/输出。本章首先介绍命名空间和匿名空间的概念,使用方法与技巧,然后介绍C++标准输入/输出,涉及C++流的特点、C++标准输入、C++标准输出以及输入/输出格式控制等内容。

● 第4章 C++面向对象基础。本章主要介绍面向对象与面向过程的比较,初步理解C++的类与对象,构造函数与析构函数的使用,this指针的分析,const数据成员与函数成员的使用,static数据成员与函数成员的使用,友元变量与友元类等内容。

● 第5章 深入讨论构造函数。本章主要介绍复制构造函数与复制赋值运算符函数的使用,本章的学习目标是让读者掌握浅复制和深复制的使用场合,在实际产品开发中能够灵活应用。

● 第6章 C++调试。本章主要介绍C++程序在开发过程中常用的调试方法与技巧。

● 第7章 C++继承。本章主要介绍继承形式,三种继承方式的区别与使用场合,子类的构造函数与析构函数,单继承子类的构造函数初始化列表,多继承子类的构造函数初始化列表以及虚继承等知识。

● 第 8 章 编译时多态。本章主要介绍由于运算符重载而产生的编译时多态,选用典型的实例介绍双目操作符重载、单目运算符重载、下标操作符重载、函数运算符重载和类型转换操作符重载的实现。

● 第 9 章 运行时多态。本章主要内容包括多重继承对象的构造与析构顺序,父子对象之间赋值的限制规则,重载、覆盖、隐藏的区别,虚函数的定义,纯虚函数与抽象类,虚函数原理,对象指针访问虚函数成员的编译器限制,突破对象访问私有函数的限制,虚函数的默认参数绑定,typeid 关键字的使用,dynamic_cast 与多态以及 C++异常机制等。

● 第10章 自定义模板。本章涉及的内容主要包括函数模板定义、函数模板实例化、类模板定义、类模板实例化、模板的全特化、模板的偏特化、类模板中赋值运算符重载函数的使用内幕等。

● 第11章 标准模板库。本章主要介绍序列式容器、关联式容器、容器适配器、迭代器、算法、空间分配器以及仿函数的使用。

致谢

首先感谢我的家人,感谢他们对我无私的支持。本书的编写共经历两年多的时间。在这期间,工作上我参与了三个重要产品的开发,时常在不同的城市间奔波;生活中,我经历了从结婚到为人父的重要阶段。高强度的工作及生活上的琐事使我分身乏术,曾多次产生放弃写作的念头,是家人的理解、支持及妻子的鼓励,才使我最终坚持了下来。其次要特别感谢我的恩师四川大学软件学院副院长唐宁九教授,在我完成学业的过程中,他做了大量的指导工作,在他的影响下,我养成了对技术严谨执着的态度,对工作追求卓越的习惯。此外感谢他在百忙之中审阅本书,提出了宝贵的修改意见,并且还为本书作序。再次感谢刘洪征、王英、周毅祥、李艳、周子越、张旭、葛成敬、刘伟、简清舟、贾英、孔洋、陈旭余、蔡俊娜、孙海浪、葛子墨、林新华、朱利利等对我的支持与帮助。最后感谢电子工业出版社的编辑李树林先生,从写书到出版过程中提出了许多有价值的参考意见,使本书不断完善。

我希望通过此书与对软件开发感兴趣的读者共同学习、共同进步。但由于水平有限,加之时间仓促,书中疏漏与不妥之处在所难免,望广大读者批评指正,提出宝贵意见及建议。同时欢迎大家通过E-mail(jason_mw@126.com)与我沟通、联系,我会尽可能回复。但由于工作时间限制,若回复不及时,还请谅解。

周建设

2015年1月3日

第1章 嵌入式开发初体验

1.1 什么是嵌入式系统

随着当今科技的快速发展,我们日常的生活习惯发生了根本性的变化,在生活中越来越离不开一些辅助性产品。就拿日常生活中一个小小的片段来说,早晨六点半你的手机闹铃响了,提醒起床;起床后开始洗漱,此刻你可能边听着手机播放的音乐边用电动牙刷刷牙,接着开始准备使用豆浆机、烤箱或微波炉做早餐,吃完早饭后准备出门,刷公交卡坐公共汽车或地铁上班,在乘车的过程中,你可能会拿出iPad玩游戏,看电影……就在起床后到上班这段时间,你已经使用了多个嵌入式产品。嵌入式产品和我们日常生活息息相关,只要你能想到的领域,都可以找到嵌入式产品的应用,小到你做的一份简单的早餐,大到登陆火星的装备。所以说嵌入式的产品包罗万象,应有尽有。

什么是嵌入式系统呢?这个名词在业内还没有统一的定义。英国电器工程师协会(U.K.Institution of Electrical Engineer)是这样定义的:嵌入式系统(Embedded System),是一种“完全嵌入受控器件内部,为特定应用而设计的专用计算机系统”。我们可以看出嵌入式系统为控制、监视或辅助设备、机器或用于工厂运作的设备。与个人计算机这样的通用计算机系统不同,嵌入式系统通常执行的是带有特定要求的预先定义的任务。嵌入式系统只针对一项特殊的任务,设计人员能够对它进行优化,减小尺寸降低成本。由于嵌入式系统通常进行大量生产,所以单个的成本较低。

嵌入式系统还有一种多数人比较认可的一种定义:以应用为中心,计算机技术为基础,软硬件可剪裁,适应应用系统对功能、成本、体积、可靠性、功耗严格要求的计算机系统。

我们也可以从另一个角度解释嵌入式系统,凡是带有微处理器的专用软硬件系统都可称为嵌入式系统。即使是没有嵌入式操作系统的单片机和DSP系统,也可以称为嵌入式系统,这些系统在完成较为单一的专业功能时具有简洁高效的特点。但管理系统硬件和软件的能力有限,在实现复杂多任务功能时,往往困难重重,甚至无法实现。

虽然嵌入式系统没有统一的定义,许多业内人士对其理解也有所差异,但有些特征是业内人士能普遍接受的,嵌入式系统通常具备如下五个特征。

➢ 系统内核小

由于嵌入式系统的硬件资源相对有限,所以内核与传统的操作系统要小得多。比如,嵌入式Linux的内核可以做到100KB左右。

➢ 专用性强

嵌入式系统是专用的系统,其中的软件系统和硬件的结合非常紧密,一般要针对硬件进行系统的移植。即使在同一品牌、同一系列的产品中也需要根据系统硬件的变化增或减不断进行修改。同时针对不同的任务,往往需要对系统进行较大更改,程序的编译下载要和系统相结合。

➢ 软硬件可裁剪

嵌入式系统的产品,其硬件和软件都是可以裁剪的,可以简单理解为它的硬件和软件由多个模块组成,我们根据实际的产品需求经行选择,不用的模块就不要添加,只用一次的模块也要设法避免。

➢ 实时操作系统

这是嵌入式软件的基本要求,而且软件要求固态存储,以提高速度。软件代码要求高质量和高可靠性、实时性。

➢ 非功能性指标要求严格

嵌入式系统产品的开发,对非功能性指标要求非常高,比如产品的体积要小,可靠性要求高(如可以在恶劣的环境下正常工作),功耗低等。还有更重要的一点是控制成本,软硬件的选择上遵循“够用就行”,不追求新潮。

1.2 嵌入式系统的体系结构

嵌入式系统由嵌入式硬件与嵌入式软件组成。嵌入式硬件以芯片、模板、组件、控制器等形式隐藏在设备内部。嵌入式软件是实时多任务操作系统和各种专用软件,一般固化在ROM或Flash中。嵌入式系统软硬兼施,融为一体,成为产品,但在开发过程中需要一些开发工具进行辅助开发。图1-1 嵌入式系统体系结构

嵌入式系统总体体系结构可以分为四个层次:硬件层、中间件层、系统软件层和应用软件层,如图1-1所示。

从图中可以看出中间件层、系统软件层和应用软件层都是嵌入式软件的重要组成部分,硬件层当然是嵌入式硬件的领地。如果把一个嵌入式产品的外壳打开,硬件层对应的就是展现在我们面前的PCB电路板,上面是各种芯片以及元器件,其中最主要的就是嵌入式处理器。开发时我们关心:上面是什么嵌入式处理器?当前流行的嵌入式处理器有哪些?

嵌入式处理器是嵌入式系统的核心,是控制、辅助系统运行的硬件单元。目前嵌入式处理器主要分为四类:嵌入式微处理器MPU、嵌入式微控制器MCU、嵌入式数字信号处理器DSP和嵌入式片上系统SoC。

1.嵌入式微处理器MPU

嵌入式处理器就是和通用计算机的微处理器对应的CPU。在应用中,一般是将微处理器装配在专门设计的电路板上,在母板上只保留和嵌入式相关的功能即可,这样可以满足嵌入式系统体积小和功耗低的要求。

嵌入式微处理器制造商:摩托罗拉、英特尔、IBM、日立、NEC、东芝、AMD、国家半导体、Zilog、IDT、富士通、Atmel、太阳、微系统、夏普、Oki、飞利浦等。

主要的嵌入式微处理器包括:Motorola PowerPC、Intel Pentium、Motorola 68000、strong ARM、MIPS、AMD X86系列等。

2.嵌入式微控制器MCU

嵌入式微控制器又称为单片机,它将CPU、存储器(少量的RAM、ROM或两者都有)和其他外设接口封装在同一片集成电路里。

嵌入式微控制器制造商:摩托罗拉、英特尔、英飞凌科技、Atmel、日立、NEC、三菱、东芝、松下、Microchip、富士、飞利浦、德州仪器、三星、三洋、索尼、Oki、凌阳科技等。

主要的嵌入式微控制器包括:MCS-51、MCS-251、MCS-96/196/296、P51XA、C166/167、68K、Z8、C540、PIC、AVR等系列。

3.嵌入式数字信号处理器DSP

嵌入式DSP专门用来对离散时间信号进行极快的处理计算,提高编译效率和执行速度。在数字滤波、FFT、谱分析、图像处理等领域应用广泛。DSP正在大量进入嵌入式市场,目前广泛应用的是TI产品TMS320C2000/C5000系列,另外Intel和Siemens也有相应的产品。

4.嵌入式片上系统SoC

SoC(System on Chip)是在一个硅片上实现一个更为复杂的系统,它追求产品系统最大的IC集成,是目前嵌入式广泛应用领域的之一。SoC最大的特点是成功实现了软硬件无缝结合,直接在处理器片内嵌入操作系统的代码模块。而且SoC具有极高的综合性,在一个硅片内部运用VHDL等硬件描述语言,实现一个复杂的系统。用户不需要再像传统的系统设计一样,绘制庞大复杂的电路板,一点点的连接焊制,只需要使用精确的语言,综合时序设计直接在器件库中调用各种通用处理器的标准,然后通过仿真之后就可以直接交付芯片厂商进行生产了。由于绝大部分系统构件都在系统内部,整个系统就特别简洁,不仅减小了系统的体积和功耗,而且提高了系统的可靠性,提高了设计生产效率。

SoC现在应用十分广泛,读者熟悉的iPhone 6采用的处理是2GHz双核64位A8,就是SoC,其实现在主流架构的芯片厂商都有自己的SoC产品在应用,比如,三星Exynos 5433、高通骁龙系列SoC、TI OMAP系列SoC、英特尔Quark系列SoC等。

嵌入式软件体系结构包含三个层次:中间件层、系统软件层和应用软件层。其中,中间件层和系统软件层的工作由底层软件工程师开发,应用软件层的工作由应用软件工程师开发。

1.3 主流嵌入式系统简介

目前市场上流行的嵌入式系统有嵌入式Linux、Windows CE、Windows XP Embedded、Vxworks、Android、iOS等,嵌入式系统都是专用的操作系统,不可能出现一统天下局面,每种嵌入式系统都有自己的优势和应用领域。下面,简单地介绍一下常用的嵌入式系统。

➢ 嵌入式Linux

嵌入式 Linux是以Linux为基础的嵌入式操作系统,广泛应用于信息家电、PDA、机顶盒、Digital Telephone、Answering Machine、Screen Phone、数据网络、Ethernet Switches、Router、Bridge、Hub、Remote Access Servers、ATM、Frame Relay、远程通信、医疗电子、交通运输计算机外设、工业控制、航空航天等领域。

使用嵌入Linux系统的优势有很多:Linux是开放源代码的,不存在黑箱技术,遍布全球的众多Linux爱好者是Linux开发者的强大技术支持;Linux的内核小、效率高,内核的更新速度很快,Linux是可以定制的,其系统内核最小只有约134KB。

此外,Linux是免费的操作系统,在价格上极具竞争力。

➢ Android

Android是一种基于Linux的自由及开放源代码的操作系统,2003年10月,Andy Rubin等人创建Android公司,并组建Android团队,22个月后被Google收购。目前Android操作系统主要用于智能手机、平板电脑和智能电视等。

Android运行于Linux Kernel之上,但并不是GNU/Linux。因为在一般GNU/Linux 里支持的功能,Android 大都没有支持,包括Cairo、X11、Alsa、FFmpeg、GTK、Pango,以及Glibc等都被移除掉了。Android又以Bionic 取代Glibc,以Skia 取代Cairo,再以OpenCore取代FFmpeg等。Android 为了达到商业应用,必须移除被GNU GPL授权证所约束的部分,例如,Android将驱动程序移到 Userspace,使得Linux Driver 与 Linux Kernel彻底分开。Bionic/Libc/Kernel/并非标准的Kernel Header Files。

➢ iOS

iOS是由苹果公司开发的手持设备操作系统。最初是设计给iPhone使用的,后来陆续套用到iPod touch、iPad以及Apple TV等苹果产品上。iOS与苹果的Mac OS X操作系统一样,它也是以Darwin为基础的,因此,同样属于类Unix的商业操作系统。它和Linux操作系统有一定渊源,都可以追溯到Unix。

iOS是商业操作系统,因此不是开源的,iOS的开发工程师主要开发iOS的应用程序,使用的开发语言是Objective-C。

➢ Windows CE

Windows CE是微软公司嵌入式、移动计算平台的基础,它是一个开放的、可升级的32位嵌入式操作系统,是基于掌上电脑类的电子设备操作系统,它是类似于精简的Windows 95。Windows CE的图形用户界面相当出色。

开发语言可以使用C++、C#、VB等,可以使用系统自带丰富的图形库快速开发出界面程序,开发效率较高。但使用选择基于Windows CE开发产品,需要向微软公司缴纳一定的版权费。

➢ Windows XP Embedded

Windows XP Embedded 是微软研发的嵌入式操作系统,是一个以组件模块展现出与Windows XP Professional操作系统一样的接口与操作模式,可依据各自需求组合出的操作系统镜像文件,确保有 Windows XP Professional 操作系统相依性以及完整的功能。它可以应用在各种嵌入式系统,或硬件规格层次较低的计算机系统,例如,很少的内存,较慢的中央处理器等。

Windows XP Embedded 基于 Win32 编程模型,由于采用常见的开发工具,如 Visual Studio.NET,使用商品化 PC 硬件,与桌面应用程序无缝集成,因此可以缩短上市时间。使用Windows XP Embedded 构建操作系统的常见设备类别包括零售销售点终端、瘦客户机和高级机顶盒。

Windows XP Embedded有一个限制,它要求目标硬件平台必须是X86架构的,而且还需要向微软公司缴纳授权费。

➢ VxWorks

VxWorks 是美国 Wind River System 公司(2009年被Intel收购)推出的一个非常优秀的实时操作系统。

VxWorks操作系统是美国WindRiver公司于1983年设计开发的一种嵌入式实时操作系统(RTOS),是嵌入式开发环境的关键组成部分。它具有良好的持续发展能力、高性能的内核以及友好的用户开发环境,在嵌入式实时操作系统领域占据一席之地。它以其良好的可靠性和卓越的实时性被广泛地应用在通信、军事、航空、航天等高精尖技术及实时性要求极高的领域中,如卫星通信、军事演习、弹道制导、飞机导航等。在美国的 F-16、FA-18战斗机、B-2 隐形轰炸机和爱国者导弹上,甚至连1997年4月在火星表面登陆的火星探测器、2008年5月登陆的凤凰号,以及2012年8月登陆的好奇号也都使用到了VxWorks。

不过如此优秀的操作系统,并不是所有场合都是合适的。通常VxWorks常用于实时性要求高、环境恶劣的场合,因为使用VxWorks需要的成本非常高,选择它之前,需要综合衡量评估后再决定。

1.4 为什么选择C++

加油站1-1:C语言的产生背景

C语言是著名的计算机科学家丹尼斯·里奇(Dennis Ritchie)创造的。1967年,Ritchie进入贝尔实验室工作。贝尔实验室是当时世界上最具创造力的地方之一,著名的C语言、C++语言和Unix操作系统都诞生于此。一开始,里奇和他的同事肯·汤普生开始研究DEC PDP-7机器,但是在这个机器上写程序很困难,只能用很底层、很高深的汇编语言。于是汤普生设计了一种高级程序语言,并把它命名为B语言。但是由于B语言本身设计的缺陷,使他在内存的限制面前一筹莫展。1973年,里奇决定对B语言进行改良,他赋予了新语言强有力的系统控制方面的能力,并且新语言非常简洁、高效,里奇把它命名为C语言,它意味着B语言的下一代。

在开发C语言的同时,里奇、汤普生和布朗(贝尔实验室的另一名科学家)还接受了一个新任务,就是在DEC PDP-7上开发一个多任务、多用户的操作系统。1969年,他们用汇编语言完成了这个操作系统的第一个版本,里奇受到一个更早的项目Multics的启发,将这个系统命名为Unix。

为了在全世界面前展现C语言强大的能力,里奇用C语言把Unix操作系统重写了一遍,这就是Unix第三版。而之前的第二版是用B语言开发的。1977年,为了推广贝尔实验室开发的Unix操作系统,里奇发表了不依赖于具体机器系统的C语言编译文本《可移植的C语言编译程序》,使C语言再向前跨出一大步,各种计算机都开始支持C语言。现在的很多高级语言都是与C语言不可分割的,比如C++、VC,或者说现在的高级平台.NET中的C#等都是以C为基础的。如果想学高级的语言,不妨先把C语言学好,再掌握那些高级语言的时候就更容易一些。

加油站1-2:C语言的优点

C语言是操作系统鼻祖UNIX的母语,目前主流的嵌入式系统或多或少都能发现UNIX的影子,所以C语言在操作系统中的地位是显而易见的。那么C语言有什么过人之处呢?一言难尽,总的说来有以下六点。

➢ 简洁紧凑、灵活方便

C语言一共只有32个关键字,9种控制语句,程序编写形式自由,主要用小写字母表示。它把高级语言的基本结构和语句与低级语言的实用性结合起来。C 语言可以像汇编语言一样对位、字节和地址进行操作,而这三者是计算机最基本的工作单元。

➢ C语言是结构化语言

结构化语言的显著特点是代码及数据的分隔化,即程序的各部分除了必要的信息交流外彼此独立。这种结构化方式可使程序层次清晰,便于使用、维护以及调试。C语言是以函数形式提供给用户的,这些函数可方便地调用,并具有多种循环、条件语句控制程序流向,从而使程序完全结构化。

➢ C语法限制不太严格,程序设计自由度大

虽然C语言也是强类型语言,但它的语法比较灵活,允许程序开发人员有较大的自由度,可以根据自己的功力任意发挥。

➢ C语言允许直接访问物理地址,可以直接对硬件进行操作

由于C语言允许直接访问物理地址,可以直接对硬件进行操作,因此它既具有高级语言的功能,又具有低级语言的许多功能,能够像汇编语言一样对位、字节和地址进行操作,而这三者是计算机最基本的工作单元。它可用于开发系统软件,如不少嵌入式OS的内核就是用C语言开发的。

➢ 生成目标代码质量高,程序执行效率高

C语言一般只比汇编程序生成的目标代码效率低10%~20%。

➢ C语言适用范围大,可移植性好

C语言有一个突出的优点就是适合于多种操作系统,如DOS、UNIX、Linux、Windows、UCOS、Vxworks等;也适用于多种机型。C语言具有强大的绘图能力,可移植性好,并具备很强的数据处理能力,因此适于开发底层系统软件、三维、二维图形和动画,它也是数值计算的高级语言。

加油站1-3:C语言的缺点

C语言的优点数不胜数,但并不是完美无瑕。C语言也有自身的一些缺点和弊端,下面我们来认识它的主要缺点。

➢ C 语言的缺点主要表现在数据的封装性上,这一点使得 C 语言在数据的安全性上有很大缺陷,这也是C和C++的一大区别。

➢ C 语言的语法限制不太严格,对变量的类型约束不严格,影响程序的安全性,对数组下标越界不作检查等。从应用的角度,C语言比其他高级语言较难掌握。

➢ 指针是C语言的一大特色,可以说C语言优于其他高级语言的一个重要原因就是它有指针,可以直接进行靠近硬件的操作,但是 C 语言的指针操作也给它带来了很多不安全的因素。C++在这方面做了很好的改进,在保留了指针操作的同时又增强了安全性。Java语言取消了指针操作,提高了安全性,适合初学者使用。

➢ 使用 C 语言开发大型应用软件时,代码的重用性较差,开发效率低,这也是面向结构开发语言普遍存在的缺点。

加油站1-4:C++是如何出现的

最初导致C++诞生的原因是在贝尔实验室的Bjarne博士等人试图去分析Unix的内核时发生的,这项工作开始于1979年4月,当时由于没有合适的工具能够有效地分析由于内核分布而造成的网络流量,以及怎样将内核模块化。同年10月,Bjarne博士完成了一个可以运行的预处理程序,称之为Cpre,它为C加上了类似Simula的类机制。在这个过程中,Bjarne博士开始思考是不是要开发一种新的语言,当时贝尔实验室对这个想法很感兴趣,就让Bjarne博士等人组成一个开发小组,专门进行研究。当时不是称为C++,而是称为C with class,这是把它当成一种C语言的有效扩充。由于当时C语言在编程界居于老大的地位,要想发展一种新的语言,最强大的竞争对手就是C语言,所以当时有两个问题最受关注:C++要在运行时间、代码紧凑性和数据紧凑性方面能够与C语言相媲美,但是还要尽量避免在语言应用领域的限制。在这种情况下,一个很自然的想法就是让C++从C语言继承过来。但是Bjarne博士更具有先见之明,他为了避免受到C语言的局限性,参考了很多语言,例如,从Simula继承了类的概念;从Algol68继承了运算符重载、引用以及在任何地方声明变量的能力;从BCPL获得了“//”注释;从Ada得到了模板、名字空间;从Ada、Clu和ML取来了异常。

因为C++语言的语法非常庞大,初学者学习较为困难,即使有些具备C语言多年开发经验的软件工程师,对使用C++开发也望而却步,感觉非常难。C++提供功能强大的语法,高效的开发机制,全面的安全,稳定措施。如果能够驾驭它,你的软件开发效率将会得到质的飞跃。

加油站1-5:C++的优势

C++号称是最复杂的开发语言之一,其优点非常多,大致如下。

➢ C++是严谨、精确、数理化的。标准定义很细致,如果你对标准深入了解,非“固有不可移植特性”代码的运行时状态是可以通过静态分析确定的;而就其本身的语法思路,是层次分明的、呼应的,有着丰富的逻辑演绎色彩的;就其语言结构而言,代码绝大多数是显式的、明确的。

➢ C++是活着的。它的标准在不断更新,变得更加严谨、易用,却保持着系统性。

➢ C++是支持底层操作的。虽然许多底层操作的具体效果会随机器变化有所差异(也就是固有不可移植特性),但如果必要,依然可以使用它们编写程序、改善效率。

➢ C++的标准是庞大、层级分明的。如果能熟练掌握全部 C++标准(语法、标准库),代码编写工作会极其精练、轻松;而如果只是用它来实验,不愿学习过多细节,它的基础特性又可以认为是一个“完备集”。

➢ C++兼容C语言的几乎所有特征(部分极少的不严谨、存在歧义的特性被去除),可以依旧采用C语言的思路,轻易加入一个C++工程的开发。

➢ C++拥有面向对象(OO)特性,“模板”等高度抽象化特性使得大型工程可以通过它进行整体管理。

➢ 它考虑了兼容性,为连接其他语言的对象文件留有接口。

➢ C++完全兼容C,可以理解成C语言是C++提供的一个子功能。

加油站1-6:C++嵌入式领域的应用场合

在早期嵌入式产品软件的开发过程中,我们基本上都是使用C语言开发的,因为C语言是一个极其精简、高效、完备的高级语言,没有任何一种语言可以代替它的地位。在早期的嵌入式时代(单片机为主)里,使用C语言开发非常高效,那个时候要做的工作基本上是一些控制以及简单的图形处理,项目的业务逻辑不是很复杂,所以使用C语言开发完全可以应对。但在技术高速发展的今天,嵌入式的硬件更新换代越来越快,市场的需求越来越复杂,仅仅使用C语言开发已经不能完全胜任现实的需求,当然在嵌入式开发中也不可能完全抛弃C语言,一个产品的开发在某个阶段甚至还需要汇编语言来完成。当今嵌入式产品开发使用的编程语言通常是汇编语言、C语言和C++(或其他面向对象语言)协同工作。项目开发在某些情况下,C语言的使用环境还不满足,如Boot Loader开发的第一阶段就必须使用汇编语言来完成,当然这样的场合非常少,但不可避免。对于底层软件的开发,通常使用C语言就可以满足需要了,例如,内核开发、驱动开发等工作。应用软件通常使用C++这类面向对象语言开发,这部分的开发代码量较大,因为不仅仅要实现产品的业务逻辑,还要完成和使用交换的界面,因此这部分程序的开发效率直接影响整个项目的开发进度。

下面分析常见的嵌入式操作系统开发产品过程使用C++语言的场合。

➢ 嵌入式Linux

嵌入式Linux的内核基本上都是使用C语言开发的。但是在嵌入式产品的开发过程中,如在Linux BSP的开发过程中,为了提高产品的开发效率,方便应用开发工程师的调用,往往需要在BSP中实现大量的中间件,这些中间件如果采用C++开发,其开发效率与重用率将大大提高。

基于嵌入式Linux的产品,稍微规模大点的,应用软件基本上是使用C++开发的。如果需要使用GUI界面,建议考虑使用Qt,Qt提供的类都是使用C++完成的。如果已经熟练使用C++,那么使用Qt开发也没有任何难度。

➢ Windows CE

如果接触过Windows CE开发,就会知道Windows CE的内核开发大部分是采用C++完成的,因此需要开发Windows CE的BSP。如果不会C++,开发工作将会困难重重,看到内核里面好多通信机制使用C++实现的代码犹如天书一样。

基于 Windows CE 的产品,应用软件的编写选择空间较大,可以选择 C++、C#、VB等,当然如果会用C++,其他都不是什么大问题。

➢ Vxworks

基于 Vxworks的产品,BSP部分开发通常使用C语言,如果应用部分的业务逻辑过于复杂,建议使用C++开发。

➢ iOS

iOS是不开源的操作系统,可以使用其提供的API编写应用程序,开发语言是Objective-C,类似于C++的面向对象开发语言。

1.5 C++编译环境介绍

1.5.1 常用的C++编译环境介绍

加油站1-7:认识Borland C++编译器

Borland C++Builder Compiler 是一个 BC 编译器。它是用来优化 BC 开发系统的工具,包括ANSI/ISO C++语言的支持,包括 RTL、C++的 STL框架结构支持。Borland C++的开发环境如图1-2 所示。图1-2 Borland C++的开发环境

加油站1-8:g++编译器介绍

g++是GNU的C++编译器。使用g++-help 查看g++编译器使用情况,格式如下:

用法:g++[选项] 文件…

选项内容见表1-1。表1-1 g++编译器选项表

以-g、-f、-m、-O、-W 或--param 开头的选项将由 g++自动传递给其调用的不同子进程。若要向这些进程传递其他选项,必须使用-W<字母> 选项。

报告程序缺陷的步骤请参见:http://bugzilla.redhat.com/bugzilla。

加油站1-9:VC++编译器介绍

Microsoft Visual C++(简称Visual C++、MSVC、VC++或VC)是微软公司的C++开发工具,具有集成开发环境,可提供编辑C语言,C++以及C++/CLI等编程语言。VC++整合了便利的除错工具,特别是整合了微软视窗程式设计(Windows API)、三维动画DirectX API,Microsoft.NET框架。目前最新的版本是Microsoft Visual Studio 2013。Microsoft Visual C++6.0的开发环境如图1-3所示。图1-3 Microsoft Visual C++6.0的开发环境1.5.2 g++和其他编译器编译的异同

Borland C++和VC++都有一个IDE集成开发环境,可以通过鼠标选择相关菜单进行编译、调试和运行工作,g++是命令行编译器,需要手动指定输出参数来进行编译、调试和运行等工作。

训练场1-1:g++的编译过程实战训练

在Linux下使用g++编译C++程序,其内部经历了如图1-4所示的编译流程。图1-4 g++编译流程

下面以hello.cc为例演示g++编译过程,hello.cc的程序清单如下。

➢ 预处理

在这个阶段,编译器将上述代码中的头文件“iostream”引入进来,在此可以用g++的“-E”参数指定g++只进行预处理过程,操作过程如下。

此时,参数“-E”起到让g++编译时在预处理结束后停止编译过程。“-o”是指定目标文件,成功后,可使用vi编译器查看预处理结束以后的C++原始程序(hello.i),部分内容如下所示。

➢ 编译

在编译阶段,g++首先检查代码的规范性,检测是否有语法错误等。在检查程序没有错误之后,g++编译器将代码编译成汇编语言。使用参数“-S”指定g++只进行编译产生汇编代码,即生成汇编语言后停止编译过程,操作过程如下。

生成的汇编程序部分内容如下。

➢ 汇编

汇编阶段是将前一个阶段(编译阶段)生成的“.s”汇编文件转化成目标文件(二进制代码),使用g++的参数“-c”让g++在汇编结束后停止链接过程,把汇编代码转化成二进制代码,操作过程如下。

此刻产生的目标文件hello.o是二进制文件,使用vi编辑器查看是乱码,如图1-5所示。图1-5 vi打开目标文件

为什么会这样呢?这是因为目标文件是二进制而不是字符内容,所以通过vi字符的形式打开目标文件是没有任何意义的。

➢ 链接

在程序的源代码中,有时要在一个源文件中实现全部的函数,例如,在 hello.cc 中,没有 cout 的实现,在头文件“iostream”中只有此函数的声明,也没有函数的实现,那么,此函数是如何实现的呢?

其实,Linux系统把“cout”函数的实现放在了“libstdc++.so.6”的库文件中,在没有参数指定时,g++将到系统默认的路径“/usr/lib”下查找库文件,找到后,再将函数链接到libstdc++.so.6库函数中去,这样,就有了cout函数的实现部分,把程序中自定义函数与这些库函数的实现部分链接起来,这就是链接阶段的工作。

完成链接后,g++就可以生成可执行程序了,具体操作如下。

此刻在当前目录下生成可执行文件hello,当执行它后,执行结果如下。

第2章 嵌入式C++开发必备知识

本章是学习C++的基础,需要读者掌握,因为这些知识点以后每个程序或多或少都会涉及。学习本章默认读者是有一点C语言开发基础的,如果感觉本章的学习有点吃力,请复习C语言基础知识。本章的侧重点不是讲解C语言语法,而是对需要掌握的基础知识进行强化。

2.1 C++程序结构

加油站2-1:认识C++程序基础结构

首先,我们从最经典的一个编程实例HelloWorld来介绍C++的第一个程序。这个程序要求读者从总体上把握,细节性的地方暂时不需要深究。在后面的章节中,相应的知识点会进行深入的剖析,下面讲述2_1.cc程序。

代码清单2_1.cc:第一个完整的C++程序。

使用g++编译2_1.cc程序,在Linux的console中输入。

生成可执行文件hello,执行这个可行文件,出现的结果如下。

如果学习过其他编程语言,对输出“HelloWorld!”的结果应该非常熟悉。虽然这个C++程序看起来很简单,但是它包含了C++程序的基本结构。下面介绍每一部分的含义及用途。

第1行到第15行是段注释,使用了/**/。在实际的产品开发中,每个C++源文件都应该在程序文件的最开始位置写上一段注释,用来说明这个程序文件实现的基本功能、软件版本、创建时间、使用的编译器、作者信息、公司信息、代码更新历史等信息。

注释的作用是说明、指示,为代码阅读者和维护者提供方便,它对程序的编译运行不会产生什么影响。

第17行是包含头文件信息。以“#”标志开始的语句是预处理器的指示语句。它们不是可执行代码,只是对编译器做出指示。在上面的实例程序中#include告诉编译器的预处理器将输入/输出流的标准头文件(iostream)引入到本程序中。这个头文件包括了C++中定义的基本标准输入/输出程序库的声明,在本程序后面的部分将用到它的功能。

这里有一点值得读者注意,不要使用C语言包含头文件的方式#include。如果使用的话,编译时将出现如下警告。

从这个警告信息中可以看出是出了什么问题,以及如何消除这个警告。在C++刚刚问世时,包含的头文件确实和C语言包含的头文件的方式一样,但是到当C++标准形成后,C++的编译器就开始支持新的标准了。至于为什么要这样做,在后面的章节有详细的分析。

第19行是使用标准库命名空间。C++标准函数库的所有元素被声明在一个命名空间中,这就是std命名空间。因此为了能够访问它的功能,可以用这条语句来表达将要使用标准名空间中元素的权利。这条语句在使用标准函数库的C++程序中频繁出现,命名空间不仅可以直接使用C++现成的命名空间,也可以自定义命名空间,这部分内容将在后面讲解。

第21行是C++函数入口,这一行是main函数的起始声明。main函数是所有C++程序的运行的入口。不管它是在代码的开头、结尾还是中间,此函数中的代码总是在程序开始运行时第1个被执行。并且,由于同样的原因,所有C++程序都必须有一个main函数,并且最多有一个main函数。

第 23 行是 C++标准输出语句,这个语句在本程序中最重要,是功能性代码行。cout 是 C++中的标准输出流(通常为控制台,即屏幕),这句话把一串字符串“Hello World!”,插入输出流(控制台输出)中。cout在的声明在头文件 iostream 中,所以要想使用cout,必须将该头文件包括在程序开始处。endl(end of line)表示一行结束,在屏幕上的显示就是换行,相当于 C 语言的“\n”,当然在 C++中,“cout<<"hello world!\n";”和“cout<<"hello world!"<

注意,这条语句以分号(;)结尾,表示这行代码的结束。C++的每一个语句都必须以分号结尾。

第24行是C++程序的返回语句,返回语句(return)引起主函数main()执行结束,并将该语句后面所跟数值返回。通常在程序执行没有出现任何错误的情况下返回0,表示这个程序成功执行,返回其他值表示错误。那么这个值返回给谁呢?它返回给系统,系统可以知道这个程序是否执行成功。例如,可执行文件为hello,我们在console上执行下面的命令。

如果生成hello的程序返回的是0(return0),屏幕上就会打印出“success”;生成hello的程序返回的是非0(return-1),屏幕上不会打印任何信息。

第27行是行注释,指示程序编写结束。

注意,并不是程序中的所有的行都会被执行。程序中可以有注释行(以//开头)、注释段(/**/)、空行(方便阅读)、编译器预处理器的指示行(以#开头)、函数的声明(本例中main函数)、程序语句(如调用cout<<),在这些语句中,有些是功能语句,有些是辅助预处理语句,有些是可以去掉的提供帮助信息的语句等,其实在项目开发中,这些语句都是需要使用的,这样的程序可读性才能得到保障,以便于协同开发。

2.2 变量与常量

加油站2-2:认识C++的变量和常量

通过2-1.cc程序的学习,也许读者觉得这个程序没有什么用,只能在屏幕上显示东西的小儿科。其实C++的功能强大,在各行各业中都能找到C++开发的相关产品。编程语言出现的初期是解决数学计算的问题。下面介绍用C++如何来实现一个简单的数学计算(9+8=?)。

在使用C++编程语言计算9+8时,首先要思考9和8从何处来,然后再考虑存放到什么地方去做加法运算,最后考虑结果存放在何处。

9和8两个数可以从键盘输入,输入后存到内存的两个不同的位置,进行加法运算再把结果保存在内存的某个位置,最后就可以从存放运算结果位置把值取出来使用。这些内存位置就是内存地址,在计算机内部都是直接通过内存地址来访问内存数据的,但是如果我们编程时也直接使用32B内存地址,那么编出来程序效率是非常低的。如何解决呢?编程语言的设计大师引入一个新东西:变量。

变量其实就是一个标识,在编程时使用这个标识比直接使用内存地址方便很多,程序的可读性,编码效率都有质的提高,程序在编译时,编译器负责把这些标号映射成内存地址。

每一个变量需要一个唯一的标识,以便它与其他变量相区别。那么变量名在定义时有什么规则呢?合法的变量名由字母、数字和下画线“_”组成。标识的长度没有限制,但是有些编译器只取前32个字符(剩下的字符会被忽略)。空格、标点和特殊符号都不可以出现在变量名中。只有字母、数字和下画线“_”是合法的。并且变量标识必须以字母开头或下画线“_”开头,必须注意的另一条规则是当给变量起名字时不可以和C++语言的关键字或所使用的编译器的特殊关键字同名,因为它与这些关键字产生混淆。例如,下面列出标准保留关键字,它们不允许作为变量名称:asm、auto、bool、break、case、catch、char、class、const、const_cast、continue、default、delete、do、double、dynamic_cast、else、enum、explicit、extern、false、float、for、friend、goto、if、inline、int、long、mutable、namespace、new、operator、private、protected、public、register、reinterpret_cast、return、short、signed、sizeof、static、static_cast、struct、switch、template、this、throw、true、try、typedef、typeid、typename、union、unsigned、using、virtual、void、volatile、wchar_t、while。

另外,不要使用一些操作符的替代表示作为变量标识,因为在某些环境中它们可能被用作保留字:and、and_eq、bitand、bitor、compl、not、not_eq、or、or_eq、xor、xor_eq。

编译器还可能包含一些特殊保留字,例如,许多生成16位码的编译器(如一些DOS编译器)把far、huge和near也作为关键字。

还有一点要注意,C++语言是区分大小写的,如变量abc和ABC表示不同的变量。

下面看什么是常量?常量可以看成变量的一种特例,可以简单地理解为定义以后就不可以改变的变量。常量的定义通常使用如下两种方法。

➢#define定义

比如:#defineMAX256

➢ 变量定义前加const

比如:constintN=99;

关于常量的一些使用细节和注意事项在后面章节中再进行详细讲解。

2.3 基本数据类型

一个运行起来的程序,在内存中的表现形式就是0和1的二进制位的组合。请读者思考一个问题,假设在内存中有一段数据是10100101,另一个段数据也是10100101,这两段数据表示的意思是一样的吗?

这个两段数据虽然看起来是一样的,但是表示的含义不一定一样。那么由谁来识别呢?识别的标准又是什么呢?执行程序的CPU可以识别两段数据是否相同,当然,这需要一个前提,就是要有标识相应数据段的数据类型的存在。不同数据类型在内存中所表示的含义是不一样的,即使外在的二进制形式是一样的,表达的含义也不一定相同。下面开始学习C++的基本数据类型。

加油站2-3:理解整型

C++提供的整数相关类型有如下三类。

➢ 长整型:long。

➢ 整型:int。

➢ 短整型:short。

这三类整数类型数据在内存中占有的空间大小在不同的编译器下有所差别,但遵循一个总的原则:long的长度≥int的长度≥short的长度。

在早期16位机时代,使用的编译器(如BC++)在long类型数据的内存中占4字节,int 和short都占2字节的空间。在现在主流32位机时代,使用的编译器(如GNU GCC 4.1.2或Microsoft Visual C++6.0),long 和 int 类型数据在内存中都占4字节,short占2字节。

由于二进制数不方便阅读和显示,因此在跟踪调试程序时,编译器工具为我们提供的内存数据通常都是按十六进制数显示的。四个二进制位用一个十六进制数表示,因此一个字节的数据在内存中需要用两个十六进制数表示。

在C++中,整数类型又可以分为有符号整数类型(unsigned)和无符号整数类型(signed)两种。说得通俗一点,有符号类型就是表示的数可正可负,无符号类型表示的数永远都是非负的。

此外long、int和short这三种数据类型是可以相互组合写在一块的,同时还可以指定是有符号还是无符号的。也许读者会有一个疑问,组合后的整型数据占有的内存空间以谁为准呢?下面我们进入训练场演练一下吧!

训练场2-1:组合整数类型数据的占有内存空间的大小

整型的三类基本类型分别是long、int和short。下面研究这三类整型组合后在内存中占有的空间分别有多大,使用的编译环境是GNU GCC 4.1.2。

可能的组合有如下几种:

➢ long long 合法类型。

➢ long int 合法类型。

➢ long short 非法类型,不支持这种写法。

➢ int long 合法类型。

➢ int int 非法类型,不支持这种写法。

➢ int short 合法类型。

➢ short long 非法类型,不支持这种写法。

➢ short int 合法类型。

➢ short short非法类型,不支持这种写法。

下面写一个程序来测序2_2.cc,程序的具体含义我们后面再去分析,这里读者只做简单了解,看下运行的结果即可。

代码清单2_2.cc代码:求整型相关类型大小程序。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载