C/C++技术丛书
点击查看第二章
点击查看第三章
C指针原理揭秘:基于底层实现机制
刘 兴 编著
第1章
C语言概述
C语言是一种通用的、过程式的编程语言,其广泛应用于系统与应用软件的开发,具有高效、灵活、功能丰富、表达力强和可移植性强等特点,是最近20多年使用最为广泛的编程语言。C语言是由美国的丹尼斯·里奇(Dennis M. Ritchie)于1969年至1973年以B语言为基础在贝尔实验室开发完成的。
1978年之后,C语言先后被移植到各种大、中、小型机及微型机上,它既可以作为工作系统设计语言编写系统应用程序,也可以作为应用程序设计语言编写不依赖计算机硬件的应用程序。目前,C语言的编译器支持各种不同的操作系统,如UNIX、Windows、Linux等。C语言的设计也在很大程度上影响了后来的编程语言,例如C++、Objective-C、Java、C#等。
1.1 C语言的起源与发展
C语言的发展历史颇为有趣,它的原型是ALGOL 60。1963年,剑桥大学将ALGOL 60发展成为CPL(Combined Programming Language);1967年,剑桥大学的Matin Richards 对CPL进行了简化,于是产生了BCPL;1970年,美国贝尔实验室的Ken Thompson对BCPL进行了修改,改名为B语言,同时用B语言编写了第一个UNIX操作系统;1973年,美国贝尔实验室的丹尼斯·里奇在B语言的基础上最终设计出了一种新的语言,他选取BCPL的第二个字母作为这种语言的名字,即C语言,丹尼斯·里奇因此被世人称为“C语言之父”。
为了推广UNIX操作系统,1977年,丹尼斯·里奇发表了《可移植的C语言编译程序》,1978年,布莱恩·克尼汉(Brian W. Kernighian)和丹尼斯·里奇出版了名著《The C Programming Language》,使C语言迅速成为世界上流行最广的高级程序设计语言,K&R C也因此确定了其事实性标准的历史地位。
随着微型计算机的日益普及,不同种C语言之间出现了不一致的问题,这一点为C语言的广泛应用带来了不便。1989年,美国国家标准局(ANSI)颁布了第一个官方的C语言标准(X3.159-1989),简称ANSI C或C89;1990年,C89被国际标准化组织(ISO)采用为国际标准(ISO/IEC9899:1990),简称为C90,这是目前广泛使用并完全支持的标准。
1999年,国际标准组织为C语言发布了新的标准ISO/IEC 9899:1999,修正了C89标准中的一些细节,并增加了更多更广的国际字符集支持,这个标准通常被称为C99,ANSI于2000年3月采用C99。
2011年12月8日,ISO正式发布了C语言的新标准C11,之前被称为C1X,官方名称为ISO/IEC 9899:2011,新的标准提高了对C++(1983年由贝尔实验室的Bjarne Stroustrup推出,C++进一步扩充和完善了C语言,成为面向对象的程序设计语言)的兼容性,并增加了很多新的特性。
1.2 C语言特性
2011年10月9日,丹尼斯·里奇去世,享年70岁,Java之父詹姆斯·高斯林(James Gosling)为此发表了纪念C语言之父丹尼斯·里奇的简短博文:“丹尼斯·里奇辞世的新闻如五雷轰顶,过去几天已经有很多资讯在报道此事,他的影响巨大,并超越了科技世界,虽然他的巨大影响可能不为人知,但完全可以感受到的是,C语言撑起了一切。我的整个职业生涯也是从C语言和UNIX中发展而来的。”全世界的计算机爱好者都以他们特有的方式纪念这位编程语言的重要奠基人,很多人在众多的国际交互论坛中发帖悼念C语言之父,全帖仅仅只用一个分号“;”(在C语言中,分号标志着一行指令语句的结束)形象地表达了人们的怀念之情。
C语言之父悄然离去,但C语言并没有因此衰退,近年来它仍然是世界主流的编程语言之一。在2019年3月的TIOBE编程语言排行榜中(如图1-1所示),C语言仍处于第2位,并呈现上升势头。
C语言主要有以下特性:
1)设计目标接近机器底层但不失跨平台性。C语言提供了许多低级处理的功能,可搭配汇编语言来使用,著名的C编译器GCC(UNIX下常用的是CC)保持着良好的跨平台的特性,以一个标准规格写出的C语言程序通过GCC(或CC)可在许多计算机平台上进行编译,甚至包含嵌入式环境以及大型机平台。
2)C语言编译生成的可执行文件短小精悍。C语言能以简易的方式进行编译,可直接处理低级存储器,仅产生少量的机器码,并且不需要任何运行环境的支持便能运行。
3)C语言虽简单但功能强大。C语言仅有32个保留字符,使用传统的结构化设计,变量具有作用域、递归等优秀功能,编译预处理使得编译更具弹性,传递参数灵活,可采用值传递和指针传递两种方式,不同的变量类型可用结构体(struct)组合在一起; 此外,C指针很容易就能对存储器进行低级控制。
1.3 开发环境搭建
下面以“helloworld”C程序(非GUI程序,运行在Windows的控制台和UNIX/Linux系统的终端)为例,讲解Windows、类UNIX/Linux平台下的开发环境搭建(本书将以UNIX/Linux平台为主,对C指针及其应用进行讲解)。
1.3.1 Windows开发环境
1. Microsoft Visual Studio
Microsoft Visual Studio(简称VS)是美国微软公司的开发工具包系列产品。VS是一个基本完整的开发工具集,它包括了整个软件生命周期中所需要的大部分工具,如UML工具、代码管控工具、集成开发环境(IDE)等。所写的目标代码适用于微软支持的所有平台,包括Microsoft Windows、Windows Mobile、Windows CE、.NET Framework、.NET Compact Framework、Microsoft Silverlight 及Windows Phone。
微软公司提供了可供免费使用的Visual Studio Community 2015(其具备所有为Windows、iOS、Android设备或是云服务器开发桌面、移动、网页应用的全套功能)。读者可通过Microsoft的网站下载Visual Studio Community 2015(下载地址为:https://visuals-tudio.microsoft.com/zh-hans/vs/older-downloads/ ),加载ISO映射文件后再进行安装。安装完毕后再启动Visual Studio Community 2015,选择“Visual C++”项目中的“Win32控制台应用程序”(如图1-2所示)。
单击“确定”按钮,出现向导对话框,选中“附加选项”区域的“空项目”之后,单击“完成”按钮(如图1-3所示)。
由于刚才建立项目时选择了“空项目”,因此需要增加C源代码文件,在源文件处点击鼠标右键,选择“添加”→“新建项”(如图1-4所示),输入源代码文件名“main.c”(如图1-5所示)。
在屏幕的左边输入“helloworld”的C语言代码(如图1-6所示)。
选择“调试”菜单的“开始执行”(如图1-7所示)。
程序经过编译后,执行效果如图1-8所示。
2. Code::Blocks
Code::Blocks 是一个开放源码的、全功能的跨平台C/C++集成开发环境,它由C++语言开发完成,使用了著名的图形界面库wxWidgets。相比Visual Studio而言,Code::Blocks是跨越平台的C/C++IDE,支持Windows、Linux、Mac OS X平台,最重要的是它遵守GPL开源协议,Windows用户可以使用它免费编译Win应用程序以及跨平台的应用程序,而无须依赖于Visual Studio。
Code::Blocks提供了许多工程模板,包括控制台应用、DirectX应用、动态链接库、FLTK应用、GLFW应用、Irrlicht工程、OGRE应用、OpenGL应用、QT应用、SDCC应用、SDL应用、SmartWin应用、静态库、Win32 GUI应用、wxWidgets应用、wxSmith工程等;它支持语法彩色醒目显示,支持代码自动补全,支持工程管理以及项目构建、调试;此外,它还支持插件、代码分析器、编译器的选择,同时还拥有灵活而强大的配置功能。
Code::Blocks的下载地址为http://www.codeblocks.org/downloads ,Windows平台下建议下载codeblocks-13.12mingw-setup.exe安装文件,因为该安装文件不仅包括Code::Blocks本身,还将含有开源免费的mingw编译器。下载安装好Code::Blocks之后,启动它,启动过程中会显示它的logo(如图1-9所示)。
启动Code::Blocks之后,选择“New”→“Project”,新建项目(如图1-10所示)。
在项目模板中选择“Console application”(控制台程序),如图1-11所示。
选择C语言为开发语言,如图1-12所示。
输入项目名称“helloworld”,同时选择项目所在的目录(如图1-13所示)。
单击“Finish”按钮,完成项目创建(如图1-14所示)。
展开左边的项目树状图(如图1-15所示),项目模板在“main.c”中自动产生了“helloworld”的源代码。
将源代码中的“Hello world!”字符串更改为中文的“您好,世界!”(如图1-16所示)。
最后,选择“Build”菜单的“Build and run”选项,编译后(如图1-17和图1-18所示),运行程序(如图1-19所示)。
1.3.2 UNIX/Linux开发环境
目前,除了Windows系统,最流行的操作系统就是UNIX和Linux了,下面分别以这两个系统的经典代表—FreeBSD(世界上最稳定的类UNIX系统,基于UNIX的衍生系统BSD)与Ubuntu(最好用的Linux系统之一)为例,讲解C语言开发环境的部署。
1. Ubuntu 开发环境
Ubuntu基于Debian发布版和GNOME桌面环境创建,是开源且免费的Linux系统,它分为桌面版和服务器版,其目标在于为用户提供一个最新的同时又相当稳定的、主要由*软件构建而成的操作系统。Ubuntu系统既可安装在全新的电脑上,也可以与Windows操作系统并存,还可以安装在虚拟机中。下面以VisualBox虚拟机中运行的Ubuntu服务器版为例进行讲解。
1)在VisualBox虚拟机中新建Ubuntu的虚拟电脑。新建虚拟电脑,将内存设置为512MB或以上(如图1-20所示),创建4GB或4GB以上的虚拟硬盘(如图1-21、图1-22和图1-23所示)。
2)下载Ubuntu服务器版。服务器版针对服务器应用对内核做了优化,同时,对虚拟机的资源要求更少,其运行速度相对于桌面版更快,因此应选择服务器版作为学习C语言以及C指针的平台。从官网链接(http://www.ubuntu.org.cn/download/server )下载Ubuntu的服务器版(12.04版)映像文件(如图1-24所示)。
3)安装Ubuntu。首先,单击“设备”→“分配光驱”,选择一个虚拟光盘,在打开的文件菜单中选择启动光盘的映像文件(从官网上下载的服务器12.04版ISO文件);然后,启动虚拟机,选择“English”语言作为系统语言(如图1-25所示)。
接着,选择“Install Ubuntu Server”(如图1-26所示)。
选择English作为安装语言(如图1-27所示),选择“United States”区域(如图1-28所示),随后配置键盘选项(如图1-29和图1-30、图1-31所示)。
按系统提示输入hostname(主机名,可以输入任意英文名字)后,再输入安装初始化时需要自动创建的用户名和密码(如图1-32、图1-33和图1-34所示,笔者输入的用户名为myhaspl,系统登录需要输入用户名全称、用户名及用户密码)。输入的用户密码需要验证(如图1-35所示)。
完成以上基本安装配置之后,安装程序提示是否加密主目录(如图1-36所示)。作为学习C语言的Linux平台无须加密,选择NO,然后安装程序显示硬盘分区方案,连续按回车键接受磁盘的默认分区(如图1-37和图1-38所示)。
在接下来的几个选项中,按回车键接受默认选项,当提示选择默认安装软件时,勾选第一项(OpenSSH server)(如图1-39所示),以便随后使用SSH客户端进行登录。
安装完毕后,重新启动,Ubuntu提示登录界面,系统安装完毕。
4)配置虚拟机的网络设备,连接互联网,虚拟电脑设置中将网卡1设置为桥接方式(如图1-40所示)。
5)使用刚才安装时建立的用户名和密码登录后,通过passwd命令设置root密码(如图1-41所示),然后通过ifconfig命令查看虚拟机自动获取的IP地址(图1-42中inet addr处表明当前分配的IP为192.168.1.239)。
6)使用putty登录虚拟机,然后部署学习本书所需要的C语言开发环境。
首先,登录虚拟机(如图1-43和图1-44所示)。
然后,设置超级用户root密码,命令如下:
$ sudo passwd root
[sudo] password for myhaspl:
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
接下来,安装GCC编译器与gdb调试器,命令如下:
$ sudo apt-get install gcc
$ sudo apt-get install make
$ sudo apt-get install gdb
2. FreeBSD开发环境
1)在虚拟机中安装FreeBSD。首先,新建FreeBSD虚拟电脑(如图1-45所示)。
2)指定虚拟电脑的光驱为FreeBSD安装ISO文件后,启动虚拟电脑,出现如图1-46所示的起始界面,选择“Install”按钮。
3)输入主机名(如图1-47所示)。
4)选择安装组件,在这里选择全部安装,最后一项的src是源码,可以不选择(如图1-48所示)。
5)进行硬盘分区(如图1-49、图1-50和图1-51所示)。
6)安装程序开始进行系统安装(如图1-52所示)。
7)安装完毕后,进行最后的配置。
先设置root账号的密码,接下来会提示你是否要增加一个普通用户,输入普通用户名及密码,以便在安装完成后作为SSH登录用户使用。输入完毕后,会出现如图1-53所示的提示界面,键入“yes”以确认刚才输入的信息,系统提示是否还要增加一个用户,输入“no”。
然后,选择exit,系统将提示是否需要手动配置(如图1-54所示),选择“no”,然后选择“Reboot”重启虚拟电脑(如图1-55所示)。
8)重新启动虚拟机后,安装GCC。
系统重新启动后会出现如图1-56所示的界面。
使用root用户名登录,然后输入密码。成功登录后,会有提示符#出现(如图1-57所示)。
安装GCC,先在#提示符下输入“sysinstall”,依次选择Configure(如图1-58所示)→ “Packages”(如图1-59所示)→“CD/DVD”(如图1-60所示)→“All”如(如图1-61所示)→“gcc-4.6.3”(如图1-62所示)后,点击“OK”后选择“Install”(如图1-63所示)。
9)允许登录的用户加入wheel组。
当服务器需要进行一些日常系统管理员无法执行的高级维护时,往往就要用到 root 权限,而wheel组就是一个包含这些特殊权限的用户池。登录用户成为wheel组的成员后,可取得root权限进行一些特权的操作,只需要修改/etc/group,即可将用户加入该组,修改的方法为:将安装过程中输入的普通登录用户添加到 wheel 组的末尾,将wheel行改成形如下面的内容:
wheel:*:0:root,myhaspl
FreeBSD下可使用ee、vi、nano三种编辑器之一修改/etc/group文件。
ee编辑器界面如图1-64所示,在屏幕上方有快捷键提示,编辑完后,按Esc + Enter键离开 ee,编辑命令如下:
#ee /etc/group
对Linux比较熟悉的读者,可安装nano编辑器,安装命令如图1-65所示,安装完毕后,可通过下面的命令修改/etc/group 文件:
#nano /etc/group
以nano编辑器为例,在wheel行的末尾加入用户名myhaspl(如图1-66所示),按Ctrl+x键,nano提示“文件已修改,是否保存”,选择“Y”,直接回车确认。
10)通过ifconfig命令查看虚拟机分配的IP地址(如图1-67所示),在inet处可以看到IP地址为192.168.1.10。
11)打开前面介绍的putty客户端登录FreeBSD,使用刚输入的myhaspl登录后输入su命令,更换用户身份为root,命令如下所示:
% su
Password:
root@myhaspl:/home/myhaspl #
12)安装glib。安装过程如下:
#cd /usr/ports/devel/glib20
root@dp:/usr/ports/devel/glib20 # make install clean
===> License LGPL20 accepted by the user
===> Found saved configuration for glib-2.36.3
===> Fetching all distfiles required by glib-2.36.3 for building
===> Extracting for glib-2.36.3
=> SHA256 Checksum OK for gnome2/glib-2.36.3.tar.xz.
===> Patching for glib-2.36.3
===> glib-2.36.3 depends on package: libtool>=2.4 - found
===> Applying FreeBSD patches for glib-2.36.3
..........................
13)喜欢vim(类似于vi的文本编辑器,增加了很多新的特性,其被推崇为最好的类vi编辑器)编辑器的,可以安装vim编辑器,安装过程如下:
myhaspl@myhaspl:~ % su
Password:
root@myhaspl:/home/myhaspl # find / -name vim
/usr/ports/editors/vim
root@myhaspl:/home/myhaspl # cd /usr/ports/editors/vim
root@myhaspl:/usr/ports/editors/vim # make install clean
=> vim-7.3.tar.bz2 doesn't seem to exist in /usr/ports/distfiles/vim.
=> Attempting to fetch http://artfiles.org/vim.org/unix/vim-7.3.tar.bz2
1.3.3 随书网盘的开发环境
FreeBSD和Ubuntu的安装过程比较烦琐,并且安装后仍然需要配置C语言开发环境,读者若有兴趣可根据前面的介绍,自行搭建属于自己的C语言开发环境。为方便Linux/UNIX基础薄弱者,本书已经将Linux系统的C语言开发环境(包括Ubuntu操作系统)制作成虚拟机文件my_ub.vdi(网盘地址:https://dwz.cn/uo3gCxWK ,提取码:457a),只需在virtualbox虚拟机中装载该文件即可使用。装载步骤具体如下。
1)新建虚拟电脑,可在此输入my_ubuntu(如图1-68所示,也可输入其他名称)。
2)选择内存大小为512MB(图1-69所示)。
3)选择“使用已有的虚拟硬盘文件”选项(如图1-70所示)后,按右下角的“选择虚拟硬盘”按钮(文件夹内包含向上箭头的图标),选择随书网盘的my_ub.vdi。装载成功后,界面如图1-71所示。
4)点击“创建”按钮,完成C语言开发环境的装载,此时,虚拟机中已经创建了一个虚拟电脑my_ubuntu(如图1-72所示)。
5)在设置的“网络”选项中,设置“连接方式”为“桥接网卡”(如图1-73所示)。
某些电脑装载虚拟文件my_ub.vdi后,可能会出现找不到网卡的情况,在这种情况下,可使用如下命令删除规则文件,让Ubuntu重新查找网卡:
$su
#cd /etc/udev/rules.d
#mkdir~/mybak
#mv *~/mybak
#reboot
使用PuTTY等工具登录服务器进行测试。
提示:PuTTY 是*的跨平台 SSH 客户端(SSH协议是目前比较可靠的远程管理手段,可以有效防止信息泄露问题),可同时在 Win32 和 UNIX 系统下模拟 xterm 终端。在Windows下可以使用PuTTY客户端登录虚拟机中运行的Ubuntu服务器,输入命令,开发和编译C程序等,PuTTY的下载地址为:
http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
虚拟文件my_ub.vdi的普通用户(通常使用这个用户登录)为myhaspl,密码为168,root用户(该用户为超级用户,通常使用myhaspl登录后,再使用su命令转到超级用户root)的密码为myhaspl,可通过下面的步骤登录服务器进行测试。
1)在虚拟机中输入ifconfig命令,查看虚拟机通过DHCP协议自动获取的IP地址。(如图1-74,inet addr处表明当前分配的IP为192.168.1.8)。
2)使用PuTTY登录,在HostName处输入虚拟机的IP地址(如图1-75所示)。
3)当询问是否将该主机的信息加入缓冲时,可选择“是”(如图1-76所示)。
4)输入登录的用户名myhaspl及密码168,登录成功后,返回当前服务器的硬盘和内存使用情况、IP地址等基本状态(如图1-77所示)。
5)当光标停留在$提示符之后,随意输入一个Linux命令(比如ls,用于列出目录中的文件)检测命令执行是否成功(如图1-78所示)。
6)上述步骤若均运行正常,则说明虚拟机加载成功,如果此时不再操作,则请输入 shutdown命令关闭虚拟机中的Ubuntu系统,命令如下所示:
myhaspl@myhaspl:~$ sudo shutdown -h now
[sudo] password for myhaspl:
myhaspl@myhaspl:~$
Broadcast message from myhaspl@myhaspl
(/dev/pts/0) at 22:21 ...
The system is going down for halt NOW!
1.4 hello,world
本节将以经典的“hello,world”程序(是指在计算机屏幕上输出字符串行“hello, world!”的计算机程序,其通常是学习编程语言的第一个示范程序)为例,讲解如何在Ubuntu操作系统下编辑、编译以及运行C程序。
1. 编辑C代码
编辑在Ubuntu系统中运行的C语言代码有以下两种方式。
第一种,使用PuTTY等SSH客户端登录服务器后使用nano或vim编辑器编写C源代码。
nano编辑器简单易用但编辑效率不高,其界面底部有快捷键提示(如1.3.2节中图1-66所示),可通过Ctrl键来控制,比如Ctrl+O键表示保存当前文件,Ctrl+W键表示进入搜索菜单等,如果要查看完整的操作列表,按 Ctrl+G键可进入帮助屏幕。vim功能强大且编辑效率较高,当习惯了vim编辑器之后,你将会有一种爱不释手的感觉,会发现它比Windows下的notepad++、codeblocks、VisualStudio更实用,不少软件工程师在Windows下使用gVim编写C程序。
vim拥有3种模式:第一种模式是插入模式,用于输入文本;第二种模式是编辑模式,用于执行命令,也称为正常模式;第三种模式是命令模式,执行格式为“冒号 命令”。
插入模式并不是默认模式,必须按下“i”来进入插入模式,在屏幕上输入C代码。按下Esc键将从插入模式转到编辑模式,该模式用于移动和操纵文本,有时会以非常有趣的方式进行。在命令模式下执行保存、查找/替换以及配置vim等功能。比如需要保存编辑的文本,在正常模式下输入“:”,进入命令模式后,输入“:w 文件名”。
使用vim编辑器编写C程序hello.c(如图1-79所示),程序完成在屏幕上输出“hello,world!”行的功能,代码如程序1-1所示。
第二种,在Windows下使用notepad++编辑好C代码之后,通过FileZilla 等SFTP客户端上传到Ubuntu服务器。
首先,在Windows系统中打开notepad++,输入程序的源代码(如图1-80所示)。
将图1-80所示的代码以hello.c文件名保存并退出。
然后,上传C程序到Ubuntu服务器中。打开FileZilla的站点管理器,输入Ubuntu服务器站点信息(如图1-81所示)。
服务器连接成功之后(如图1-82所示),上部是连接信息,方框内左部为Windows系统(即客户端本机)磁盘目录,方框内右部为Ubuntu系统(需要连接的服务器)磁盘目录。
将刚才编写的C程序源代码文件(所示图1-83所示的方框内的左中部)用鼠标拖动到Ubuntu服务器的myhaspl用户目录(如图1-83所示的方框内的右部)中。
文件上传完成后的界面如图1-84所示。
2. 编译C程序
通过“gcc -o 执行文件名 源代码文件”的命令格式编译“hello,world”程序:
myhaspl@myhaspl:~$ cd learn1
myhaspl@myhaspl:~/learn1$ gcc -o hello hello.c
也可以使用make程序进行编译。编写如下所示的makefile文件:
hello:hello.c
gcc hello.c -o hello
clean:
rm hello
执行make命令完成编译:
myhaspl@myhaspl:~/learn1$ make
gcc hello.c -o hello
3. 运行C程序
直接输入执行文件名,运行程序:
myhaspl@myhaspl:~/learn1$ ./hello
hello,world!
1.5 小结
本章首先概述了C语言的起源、发展,C标准从最初的K&R C发展到C99,直到最新的C11,每次新标准的发布都意味着向C语言注入了更实用、更强大的功能;接着,列举了C语言的特点,相比较于其他编程语言而言,C语言最大的优势就是操作简单且功能强大;然后分别以Windows、Ubuntu、FreeBSD操作系统为例,细致讲解了C语言开发环境的搭建,同时对随书网盘所附的虚拟机开发环境进行了解说;最后,以helloworld为例,简述了如何编辑、编译和运行C程序。