1 概论
1972年Dennis Ritchie发明了C语言,而后Dennis Ritchie又使用C语言重写了Unix系统,自那以后C语言逐渐受到了全世界大多数编程爱好者的喜爱,后期的主流操作系统Linux,MacOSX,Windows的绝大部分底层都是采用C语言来实现的,主流编程语言Java,PHP,Python的底层也是C语言实现的。
而伴随着移动互联网(Android,IOS),云计算,大数据以及物联网的不断发展,C语言会占据更加广阔的市场,因此C语言是作为一名ITMan必须深入掌握的语言。
2016年4月 TIOBE 编程语言排行榜(前20名)
2 计算机体系结构
计算机通常都是由硬件和软件组成的,其中硬件主要包含CPU,内存,硬盘和网卡以及IO设备组成。
程序是运行在计算机硬件之上的,那么计算机硬件是由哪些部分组成的呢?
计算机硬件主要包含CPU,内存,硬盘和网卡以及IO设备组成
下面简要介绍下各个组件之间的作用:
CPU主要是用来计算数据和控制各个硬件设备协助完成数据输入输出等等
内存主要是用来临时存储运算的(少量)数据,断电后数据会丢失
硬盘主要是用来永久存储大容量(TB)的数据
网卡用于在网络上传输数据
IO设备在CPU的控制下完成数据输入(通常是鼠标键盘完成)以及输出(通常是声卡,显卡或者打印机完成)
在程序故障诊断时通常都需要考虑单机的CPU,内存和磁盘以及网卡的性能瓶颈
软件的出现实现了人与计算机之间更好的交互方式。
软件分类主要分成系统软件和应用软件两种,其中系统软件有基于命令行交互方式,运行于服务器端的Unix(Solaris13),Linux(Redhat7.0),基于图形化界面,运行于PC,笔记本上的Ubuntu16,Windows10,MacOSX10.11,基于语音手势识别,触控滑动,运行于移动终端(手机,电视,嵌入式设备)的Android和IOS等主流操作系统,其中Android是基于Linux发展而来,IOS是基于MacOSX发展而来。
应用软件主要是运行在PC或者是移动终端的操作系统之上,用于解决生活的各种需求,例如购物,聊天,听音乐,看电影,收发邮件等等,例如,天猫京东支付宝,微信,天天动听,迅雷影音,FoxMail等等。
而目前主流技术趋势是基于Android和IOS的移动互联网以及将来(5-10年后)即将火爆的物联网
3 编程语言发展史
程序就是指令系统加上数据集 组成,而每个CPU都有自己的指令系统(由二进制的机器码010101序列组成),PC上一般是X86指令系统,手机上是ARM指令系统,这也就意味着PC上的程序不加修改就不能到手机上运行,手机上的程序不加修改也不能到PC上运行,这也就是最早的编程语言-机器语言的由来,它的特点是高效,不能移植,不易开发和后期维护等等。
斗转星移,汇编语言和编译器的出现解决了需要记住非常多的机器指令的难题,但是还是没有从根本上解决移植性的问题,只是将机器指令转换为易懂的英文单词,然后由编译器编译成机器指令,因为计算机终归揭底智能识别0001110100110机器指令,而且汇编语言是面向机器的,不同机器的汇编指令是不相同的。
这里的代码是演示Windows上将汇编语言嵌套在C语言中使用,完成两个变量相加的结果
void use_asm(){
int a, b, c=0;
a = 4;
b = 6;
printf("a = %d \t b=%d\tc=%d \n",a,b,c);
_asm{
mov eax, a;
add eax, b;
mov c ,eax;
}
printf("a = %d \t b=%d\tc=%d\n", a, b, c);
}
void main(){
use_asm();
getchar();
}
时光再流转,在1972年C语言的诞生,一种以面向过程,高效和可移植性的编程语言,C语言的出现,屏蔽了底层硬件的不同,使得开发人员可以集中精力在业务逻辑的实现上,适合做系统软件,驱动程序的开发,同时它也存在着对系统平台库的严重依赖,只有标准C的部分是可移植(所有的主流操作系统都实现了C语言的标准库函数),软件实现周期较长等缺点。而后期的C++,Java,C#,Python,PHP等编程语言在很多方面都吸收了C语言的优点,新增了如面向对象(OO),更加完善的API接口以及提供了日常开发中所需的丰富的类库等诸多的特性,更加适合做应用软件开发。
目前流行的NoSQL数据库Redis就是采用标准C开发的,而MongDB是采用C++语言开发的。
4 C语言编程环境
由C语言编写的程序可以运行在各大主流操作系统之上,而且标准C的部分是可移植的。而且为了方便开发人员开发,测试和部署应用程序等,还提供了强大的集成开发环境,在C语言学习初期可以采用Windows10+VisualStudio2015的C语言环境,后面的博文将会使用VisualStudio2015(后面都会简称为VS2015)作为开发C语言的IDE,在讲到C语言的平台差异性时会使用Linux系统的VIM编辑器(该编辑器只能写简单的C程序)。
下面是各大主流操作系统对应的IDE
操作系统
IDE
Windows10
VisualStudio2015
Linux(Ubuntu16)
QT5.5
MacOSX10.11/IOS9
XCode7.2
Android6
AndroidStudio2.0
除此之外还有些跨平台的IDE,例如CodeBlocks,Eclipse等等。读者们可以根据自己的喜好以及平台来选择对应的IDE。
5 使用VS2015开发C语言版本的HelloWorld
helloworld程序通常是学习一门语言的入门程序,如果能够正常编译运行helloworld,就表示编译和运行环境已经搭建完成。
1 VS2015安装说明
VS2015安装时可以选择指定的模块安装,我的机器是i5+12G内存,安装所有的模块大概耗时6个小时,使用VS2015还可以开发Anndroid IOS程序。
安装完成之后需要使用Microsoft公司的账号登录之后才能免费使用,这里提供一个企业版的激活码:HM6NR-QXX7C-DFW2Y-8B82K-WTYJV,过了免费的时间之后可以使用该激活码激活。
送上启动界面:
2 使用VS2015创建C语言的Project
可以使用Ctrl+Shift+N快捷键实现创建一个新的工程
点击确定之后就会看到如图所示的内容了:
下面对该项目的目录结构做一个说明:
VS2015有个解决方案的概念,一个解决方案下面可以存在多个项目,例如这里已经创建了一个和解决方案同名的项目WindowsC,该项目下有两个重要的目录,分别是头文件和源文件,头文件用于存放函数声明,源文件就是存放开发人员编写代码的目录了。
需要注意的是同一个解决方案下不能存在相同名字的源文件,当一个解决方案下存在多个项目时如果要运行指定的项目,需要将其设为启动项后运行,而且同一个项目项目只能有一个main函数,否则无法编译通过
3 使用VS2015实现C语言的helloworld
helloworld的本质就是在控制台上打印一串字符串,windows的命令行下可以使用echo命令实现类似的功能。
而要使用C语言完成这个功能则需要借助于printf函数来实现,而要想使用该函数,必须使用#include
#include <stdio.h>//引入位于系统路径(C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt)标准输入输出头文件
#include <stdlib.h> //引入位于系统路径(C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt)标准库函数头文件
头文件编写完成之后就可以编写源文件用于实现helloworld了
helloworld源码实现:
#include "common.h"
/*
定义程序主入口
@author Tony [email protected]
@since 2016-05-12 19:26
*/
void main() {
printf("Hello World \n");
system("echo Hello World Again\n");
system("pause");
return;
}
HelloWorld源程序解析
#include "common.h" //包含共通的头文件,会将头文件的内容替换到HelloWorld.c源文件中 当需要包含系统路径下的头文件时使用<>
/*
每个C程序要想运行,必须定义一个入口点,即main方法,方法的参数可以为空
Windows平台的编译器规定main方法的返回值为空
Linux平台的编译器规定main方法的返回类型为int
@author Tony [email protected]
@since 2016-05-14 19:32
*/
void main() {
printf("Hello World \n");//打印字符串Hello World并换行
system("echo Hello World Again\n");//调用系统的echo命令输出指定的字符串
system("pause"); //程序暂停,输入任意键程序会退出
return; //返回为空 return之后的语句都不会执行!
}
上述代码中使用了C语言的两种注释,分别是单行注释和多行注释,注释是描述程序的意图,方便后期维护,编译器会删掉注释的内容,而不影响程序的逻辑。
编写完成helloworld之后就是运行程序观察执行结果了,当然这中间包括了非常复杂的过程,后续博文会详细讲解背后的原理,现在只要按下F5就可以观察到如下的运行结果了。
6 C语言的运行原理
在使用VS2015编写helloworld的源代码以及相关的头文件时,使用其提供的快捷键F5编译并运行了程序,但这背后实际上还包含了预编译,转汇编,编译,链接四个步骤。
接下来将采用Linux(CentOS7)操作系统的C语言环境结合GCC编译器的一些编译选项来解剖C语言的运行原理。
环境说明:
宿主机操作系统:Windows10 企业版
虚拟机:CentOS7 企业版
编辑器:gedit
SSH远程连接工具:XShell,XManager
[[email protected] Desktop]# cd /home/guanglei/Desktop/ #进入桌面
[[email protected] Desktop]# gedit helloworld.c #使用gedit编辑c语言的源文件
helloworld.c源代码如下:
#include "common.h"
#include <stdio.h>//引入跨平台的标注输入输出头文件
#include <stdlib.h> //引入跨平台的标准库头文件
/*
定义程序主入口
@author Tony [email protected]
@since 2016-05-14 19:45
*/
int main(){
printf("This program is running CentOS7 \n!!!");
system("date"); //显示当前系统日期
system("ps -ef|grep java");//查看运行的java进程
return 0;// 返回0表示正常退出
}
使用gedit编辑helloworld.c效果示意图:
编写完源码之后就可以使用Linux(CentOS7)提供的gcc编译器来编译源程序了。
第一步 预编译
预编译就是将include包含的头文件的内容替换到源文件中,同时将代码中注释的内容删除,使用gcc编译器的-E选项实现预编译:
[[email protected] Desktop]# gcc -E helloworld.c -o helloworld.e #-o表示输出的文件名称
[[email protected] Desktop]# gcc -E helloworld.c -o helloworld.e #使用geit查看预编译后的结果
第二步 转汇编
C语言的源代码计算机是不能识别的,因此在运行之前需要将其转换成汇编语言,可以通过gcc编译器的-S选项来实现转换成汇编:
[[email protected] Desktop]# gcc -E helloworld.c -o helloworld.e
第三步 编译
计算机只能识别二进制的机器码,编译器会将汇编指令转换成二进制的机器码,可以使用gcc编译器的-c选项来实现转换成二进制:
[[email protected] Desktop]# gcc -c helloworld.c -o helloworld.o #编译成二进制
第四步 链接
在编译成机器码之后程序还不能够直接运行,还需要一个链接的过程,就是将C语言库函数以及源码转换后的二进制文件打包到一起组成可执行的文件。
这些步骤可以一次实现(预编译,编译和链接)
[[email protected] Desktop]# gcc -o helloworld.o helloworld.c
[[email protected] Desktop]# ./helloworld.o #运行改程序并显示结果
This program is running CentOS7
Wed May 11 22:33:05 PDT 2016
root 6208 6206 0 22:33 pts/0 00:00:00 sh -c ps -ef|grep java
root 6210 6208 0 22:33 pts/0 00:00:00 grep java
7 Windows系统常用命令
Windows系统包含大量的系统命令,提供了日常使用的绝大部分功能,实际上Windows系统图形化界面操作的背后就是在调用这些系统命令,学会这些常用的命令可以让我们更加方便和快捷的使用Windows系统提供的功能。
要想使用命令,必须启动一个cmd命令窗口,使用Windows+R,输入cmd后即可启动命令行窗口,
cmd运行示意图:
当看到如上图所示的命令行界面之后就可以输入Windows提供的命令来完成日常绝大部分操作的功能了。
下面将介绍常用的Windows命令行提供的指令
文件管理命令集
dir #列出当前目录列表
md #创建目录
rd #删除目录
cd #进入指定的目录(windows只能在当前盘符下切换)
del #删除文件
exit #退出cmd命令行
type #显示文件内容
实用程序和系统管理命令集
calc #计算器
notepad #记事本
mspaint #画图
timedate.cpl #日期和时间
cleanmgr #磁盘清理工具
CompMgmtLauncher #计算机管理
desk.cpl #屏幕分辨率
perfmon #计算机性能检测器
powercfg.cpl #电源选项
regedit #注册表编辑器
shutdown -s
services.msc #本地服务设置
Msconfig #系统配置
msinfo #系统信息
mstsc #远程连接
explorer #资源管理器
firewall.cpl #防火墙
taskkill /f /im process.exe #关闭指定的进程
appwiz.cpl 程序和功能(添加或者卸载程序)
control 控制面板
除了在cmd命令行窗口调用这些程序之外,C语言提供了一个位于stdlib.h头文件的system函数来调用各大操作系统(Windows,Linux,MacOSX,Android,IOS都可以)。
使用system函数调用Windows命令示例:
共通的头文件
#define _CRT_SECURE_NO_WARNINGS//关闭VS2015的安全检查
#include <stdio.h>//引入位于系统路径(C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt)标准输入输出头文件
#include <stdlib.h> //引入位于系统路径(C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt)标准库函数头文件
#include <Windows.h> //引入Windows头文件
源代码
#include "common.h"
/*
根据传递的命令字符串调用系统命令
*/
void call_system(char str[]) {
printf("你输入的要执行的命令是%s\n", str);
system(str);
}
/*
程序主入口
@author Tony [email protected]
@since 2016-05-14 09:40
*/
void main() {
char str[100] = { 0 }; //定义一个字符数组 数组中的每个元素初始化为0
printf("请输入system函数调用windows系统命令的名称\n");
scanf("%s", str); //将输入的命令字符串赋值给str
call_system(str);
call_system("pause");
}
使用Windows系统库函数ShellExecuteA函数实现异步打开和关闭程序
共通的头文件
#define _CRT_SECURE_NO_WARNINGS//关闭VS2015的安全检查
#include <stdio.h>//引入位于系统路径(C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt)标准输入输出头文件
#include <stdlib.h> //引入位于系统路径(C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt)标准库函数头文件
#include <string.h> //引入字符串头文件
#include <Windows.h> //引入Windows头文件
#include "common.h"
/*
根据传递的字符串执行system函数调用系统命令
@author Tony [email protected]
@since 2016-05-14 09:29
*/
void start_process(char str[]) {
printf("你输入的要执行的命令是%s\n",str);
char execute_str[100] = {0};
strcpy(execute_str, "start ");
ShellExecuteA(0,"open",str,0,0,1); //异步执行打开指定的进程
}
/*
关闭指定的进程
*/
void kill_process(char str[]) {
printf("你要终止的进程名称为%s\n",str);
char kill_str[100] = { 0 };
strcpy(kill_str,"start ");
strcat(kill_str, "taskkill /f /im ");
strcat(kill_str,str);
strcat(kill_str, ".exe");
printf("执行结束进程的字符串内容是%s",kill_str);
system(kill_str);
}
/*
定义程序主入口
@author Tony [email protected]
@since 2016-05-14 09:26
*/
void main() {
char str[100] = {0}; //定义一个字符数组 数组中的每个元素初始化为0
printf("请输入system函数调用windows系统命令的名称\n");
scanf("%s",str); //将输入的命令字符串赋值给str
start_process(str);
Sleep(5000); //程序此处会暂停5S
kill_process(str);
system("pause");
}
欢迎扫描下方的二维码,关注微信公众服务号-艺无止境,分享IT技术干货。