我的全栈之路-C语言基础之C语言概述与开发环境搭建
- 1.1 信息技术发展趋势
- 1.2 浅谈计算机系统架构
- 1.3 程序和指令
- 1.4 计算机编程语言发展史
- 1.5 程序的编译和解释
- 1.6 计算机语言应用场景
- 1.7 C语言概览
- 1.8 C语言集成开发环境搭建
- 1.9 Visual Studio Code实现C语言HelloWorld
- 1.10 Visual Studio 2019集成 GitHub
- 1.11 Visual Studio 2019实现HelloWorld
- 1.12 HelloWorld详解
- 1.13 注释
- 1.14 Windows常用命令
- 1.15 system函数的使用
- 1.16 C语言的编程流程
- 1.17 C程序的运行流程
- 1.18 Visual Studio 2019使用技巧
1.1 信息技术发展趋势
目前信息技术主要经历了互联网、移动互联网以及以大数据、云计算、物联网、人工智能、区块链等为代表的新兴技术三个阶段。
-
互联网
互联网自从20世纪90年代逐渐兴起,主要是通过网络连接了世界各地的PC机,笔记本以及背后提供数据服务的大型服务器集群。
其中绝大多数PC机都运行着Windows,macOS操作系统,而服务器主要是以类Unix(CentOS,Ubuntu)占据主要市场。
依靠互联网成长起来的公司有Apple、Google、Amazon、Microsoft、Baidu、Alibaba、Tencent。 -
移动互联网
移动互联网主要从2010开始爆发式增长,主要是通过网络连接了世界各地的移动设备(最典型的就是手机),它们绝大多数都运行着Android,iOS操作系统。
依靠移动互联网成长起来的公司有字节跳动、蚂蚁金服、小米、美团、滴滴。 -
大数据、云计算
随着用户的爆发式增长,以海量数据为基础的大数据、云计算技术在Google、Amazon、Apple、Baidu、Alibaba、Tencent等大型互联网公司有着广泛的商业应用场景。 -
物联网
物联网会以手机作为中枢,通过物联网连接所有的智能设备,包括智能家居、汽车、电视等嵌入式设备,目前国内的小米、华为等在智能家居、电视、汽车等领域广泛布局,2019年8月华为发布了鸿蒙系统。 -
人工智能
人工智能(AI)作为当前最火爆的技术,国内的Baidu、Tencent、Alibaba等互联网公司逐渐根据自身的核心业务开始布局,Alibaba最早将人工智能技术布局在电商和物流领域,而Baidu开发出了对话式人工智能操作系统Dueros和自动驾驶平台Apollo,Tencent则是在游戏领域应用人工智能。 -
区块链
区块链经历了数字货币、智能合约和超级账本三个阶段,区块链技术可以广泛使用在金融、供应链、物流、公共服务等领域,解决互联网的信任问题,目前蚂蚁金服、京东已经有大量的区块链应用落地。
1.2 浅谈计算机系统架构
1.2.1 计算机系统架构概述
计算机是一种用于高速计算的电子机器,可以进行数值运算、逻辑判断,还有存储记忆功能,且能够通过编写程序实现来自动、高速的处理数据。
计算机系统由硬件系统和软件系统组成,由软硬件共同协作完成人们日常生活和工作中的各种任务:
- 微信聊天:微信监听键盘输入的数据,并放到内存,然后传给网卡,通过网络传递给另外一个网卡,再从网卡传递到内存,显示在显示器上。
- QQ音乐:QQ音乐将音乐数据加载到内存上,然后写到声卡上。
- 腾讯视频:应用程序将视频数据加载到内存,然后写到显卡上。
- Office写文档:Office将内存中的数据写入到磁盘上。
- Office读文档:Offcice将磁盘的数据加载到内存,然后显示在屏幕上。
1.2.2 计算机硬件系统
现在计算机是由运算器、控制器、存储器、输入设备和输出设备五大部分组成,它们各司其职,完成了数据的计算、存储、传输等常见任务。
-
CPU
CPU也就是中央处理器,由运算器和控制器所组成,其作用是从内存中获取指令并执行后将结果返回给内存或写入磁盘和控制其他设备协同工作。 -
内存
内存是采用编址存储,其主要作用是作为程序的工作区,程序运行时会将指令和数据都加载到内存,内存中的数据断电后会丢失,用于临时存储小容量数据。 -
硬盘
硬盘是用于永久存储海量数据,按照读写性能不同分为机械硬盘和固态硬盘两大类。 -
IO设备
IO设备用于数据的输入和输出,其中常见的输入设备包含鼠标、键盘,常见的输出设备包括声卡、显卡。
网卡也是属于IO设备的一种,主要用于网络上的数据接收和发送。
在后期程序排查错误时除了要考虑程序本身的错误以外,还要考虑计算机硬件故障,例如内存不足,磁盘写满,网络不通等问题
每个计算机组件的IO性能也各不相同,CPU、内存、磁盘都遵循容量越大、IO性能越差的特点。
在后期优化程序时需要考虑程序时间复杂度和空间复杂度的问题。
1.2.3 计算机软件系统
软件的出现实现了人和计算机更好的交互,它是由开发人员采用某种编程语言(C/C++/Java等等)编写的一系列指令以及不同业务场景产生的数据组成。
通常将软件分为系统软件和应用软件
系统软件:驱动程序、操作系统、语言处理程序等都是属于系统软件。
驱动程序是硬件厂商使用编程语言(C/C++)编写的程序,在使用硬件(例如打印机、显卡等等)前必须安装对应的驱动程序。
操作系统是负责通过驱动程序管理硬件资源,同时给应用软件提供运行平台,目前主流的操作系统有Windows,Linux,macOS,Android,iOS。
语言处理程序是用于将编程语言编写的源程序编译或者解释成对应平台的机器语言。
应用软件:微信、支付宝、淘宝、Office都是属于应用软件,它们都是运行在操作系统之上的。
运行在不同操作系统之上的软件交互方式也不一样,Linux上的软件通常是使用字符界面的交互方式,运行在Windows,macOS上的软件通常是以鼠标、键盘操作的交互方式,运行在Android,iOS上的软件通常是以手势触控、语音等交互方式。
1.3 程序和指令
程序是为了完成某项任务(例如聊天、听音乐)而使用某种编程语言(例如C/C++)编写的一组指令序列。
而指令是计算机程序控制的最小单位,由操作码和操作数组成,操作码是计算机要执行什么操作,例如加减乘除操作,而操作数具体执行的对象,具体的数据以及数据的位置。
所有指令的集合称为指令系统,常见的PC机指令系统有Intel X86指令集,常见的手机指令系统有ARM,因此手机上的程序不加修改是不能直接在PC机上运行,因为不同的指令集是不兼容的。
那么计算机是如何处理程序的?
根据冯诺依曼计算机结构的原理,计算机的工作流程大致如下
- 当用户从计算机中打开程序时(鼠标点击桌面的快捷方式图标),程序开始执行。
- 操作系统将程序的内容和相关的数据传送到内存中。
- CPU根据程序内容从内存中读取指令。
- CPU分析、处理指令,并为下一条指令做准备
- 取下一条指令并分析、处理,如此重复操作,直到执行完程序中的全部指令,最后将计算的结果放到指令指定的存储器地址中。
以网易云音乐播放音乐为例子
- 用户双击网易云应用程序播放音乐
- 网易云应用程序的指令和数据加载到内存
- CPU从内存中读取并分析指令然后通过操作系统调用驱动程序
- 驱动程序调用声卡播放音乐
1.4 计算机编程语言发展史
任何事物都是从无到有,逐步发展壮大起来的,编程语言也是一样。
计算机程序设计语言经历了机器语言到汇编语言和高级程序设计语言三个阶段,其特点是使得程序员用编程语言开发、测试、部署应用程序越来越方便、高效。但是是以牺牲效率为代价,但是随着计算机硬件的发展,绝大多数应用场景的效率损失可以忽略不计。
- 机器语言
计算机发展的最早期,程序员编写程序采用二进制的指令(010010101)来实现的,而每种CPU都有各自不同的指令系统(Ultra SPARC/Intel X86/ARM),因此在不同的机器上使用不同的机器语言实现。其特点是性能特别高效,而面向机器编程也就意味着不能移植,需要手动处理底层硬件的差异性,而且二进制的指令难以理解和维护。 - 汇编语言
随着时代和计算机技术的发展,汇编语言和编译器的出现解决了机器语言需要记住非常多的二进制机器指令的难题,但是还是没有从根本上解决移植性的问题,只是将机器指令转换为易懂的英文单词,然后由编译器编译成机器指令,因为计算机终归揭底只能识别二进制的0001110100110机器指令,而且汇编语言是面向机器的,不同机器(SPARC/Intel X86/ARM)的汇编指令是不相同的。 - 高级程序设计语言
高级程序设计语言的高级之处体现在开发人员在编写程序时无需关心计算机底层硬件差异而只需要专注于业务模块实现即可。甚至是可以实现 一次编译,到处运行,这里以Java为例子:通过实现不同平台的JVM,编译生成的字节码文件可以在任意的JVM上运行。
高级语言主要分为面向过程和面向对象两种,其中典型的面向过程编程语言就是C,面向对象的编程语言有Java,C++等等。
高级语言通常都需要编译器或者是解释器将源码编译或者解释后执行。
1.5 程序的编译和解释
由于高级编程语言和计算机底层语言是互不相通的,计算机最底层只能识别01010这种二进制的机器指令,因此需要使用工具进行语言之间的转换。这个就是程序编译或者解释的由来。
为了理解程序编译和程序解释,这里引入两种语言,分别是高级计算机语言L1,以及低级计算机语言L0。
-
程序编译
开发人员使用高级编程语言L1编写的应用程序通过编译器生成成计算机底层能够识别的低级语言L0,L0就是计算机实际执行的语言,而编译器生成的计算机底层识别的二进制机器指令过程就是程序编译。常见的编译型语言有C/C++/Objective-C/Go -
程序解释
首先使用L0语言实现另外一个程序,也就是解释器,然后将开发人员使用高级语言L1编写的应用程序作为输入,每一句L1编写的程序都会在L0中作为等价的转换然后执行,解释的过程就是由L0编写的解释器去解释L1程序。常见的解释型语言有PHP,Python,JavaScript。
而Java和C#属于编译+解释型语言,以Java为例子,Java程序在运行之前首先被编译成Java字节码,然后在JVM虚拟机上解释运行。
1.6 计算机语言应用场景
如果想知道目前主流的编程语言有哪些,可以访问tiobe 首页获取编程语言排行榜。
2019年9月编程语言排行榜Top20
根据Tiobe排行榜得知,Java/C/Python分别排在前三名, 随后紧跟着C++,C#,JavaScript等等。
每种编程语言都有自己擅长的应用场景。
编程语言 | 应用场景 |
---|---|
C | 硬件驱动、操作系统、系统软件 |
C++ | 系统软件、网络通讯、科学计算 、游戏 |
C# | Windows应用,Web应用、游戏 |
Java | 大型互联网应用(淘宝、天猫),Android,大数据 |
Go | 高并发、区块链、微服务 |
Kotlin | Android应用开发 |
Swift | macOS,iPhone,iPad应用开发 |
Python | 人工智能、机器学习、自动化运维、数据分析 、图形处理 |
JavaScript | 浏览器端、服务端、PC桌面 |
Scala | 大数据开发 |
那么如果你作为初学者,面对如此之多的编程语言,到底应该先从哪门语言上车呢?如果你想深入的学习其他语言和架构相关的知识之前建议熟练掌握C语言。因为C++/Java/C#等编程语言都模仿了C语言。无论哪种语言,都是实现目标的工具,而不是目标本身。
而不出意外的话,我的全栈之路系列会覆盖上述的十种编程语言,目的是实现全平台开发,带领大家一起学习,逐步成长为开发工程师。
1.7 C语言概览
1.7.1 C语言发展简史
C语言凭借其高效率、良好的移植性、功能强大的特性在操作系统、硬件驱动以及系统应用开发占据广阔的市场。
- 起源
1972年,贝尔实验室的Dennis Ritchie和Ken Thompson在开发Unix操作系统时设计了C语言,该操作系统的90%以上的代码都是由C语言实现,后期的Linux,macOS,Android,IOS都是基于Unix发展而来的。 - 标准
1987年Dennis Ritchie和Brian Kernighan编写了The C Programming Language第一版是公认的C标准实现,而没有定义C库。
而后期ANSI/ISO先后于1990年、1999年和2011年发布了C90标准、C99标准和C11标准,该标准定义了C语言和C标准库。
1.7.2 C语言特性
C语言作为面向过程的高级程序设计语言,能够轻松的实现自顶向下的规划、结构化编程和模块化设计,这样使得程序结构更加简洁,可扩展性强以及更加容易维护。
而且C语言有着高效(执行速度快)、功能强大(嵌套汇编)以及可移植性(标准库可移植)、功能强大等优点,而且也存在着对系统平台库依赖严重,由于编程风格自由,经验不足也会容易导致出错,编写代码实现周期长,同样的代码在不同的操作系统(或者编译器)下可能会有不同的表现等缺点。
1.7.3 C语言应用场景
C语言偏向硬件驱动、操作系统、底层应用(数据库、编译器)、嵌入式应用开发、游戏引擎等应用场景。
硬件驱动的绝大部分实现是由C语言和汇编语言实现的。
主流操作系统(Unix,Linux,macOS,Windows,Android,iOS)的底层实现都是由C语言和部分汇编实现的。
C++,Java,Python,Swift的编译器或者解释器都是由C语言实现的。
Git,Nginx,Redis,MySQL都是使用C语言实现的,而且都是开放源代码的,可以在GitHub中获取到,可以通过阅读源码提升自己的设计和编码能力。
1.8 C语言集成开发环境搭建
目前主流的操作系统(Windows,Linux,macOS)都有完善的C语言集成开发环境,用于编辑、编译、调试、打包部署C程序。
操作系统 | 开发工具 |
---|---|
Windows10 1903 | Visual Studio 2019 |
macOS10.14 | XCode10.3 |
Ubuntu18.04 | QT5.13 |
Windows作为世界上最流行的桌面操作系统,当前最新版本为Windows10 1903,VisualStudio作为Windows上最强大的集成开发环境,可以开发Windows软件,游戏,Web应用等等,最新版本为VisualStudio2019 16.2.2。
Ubuntu作为最受欢迎的桌面版Linux系统之一,推荐采用跨平台的集成开发环境QT来编写C/C++程序。
macOS平台推荐使用XCode来编写C/C++程序,而且XCode在macOS系统上是自带的,无需额外安装。
除此以外还有些跨平台的C/C++ 开发工具,例如来自Jetbrains公司的CLion也可以用来编写C/C++程序。
关于IDE的安装以及使用,它们的官网都提供了详细的教程,同学们可以自行去查阅。
C语言学习过程中会使用Windows10 1903+Visual Studio 2019作为主力开发环境,如果没有特别的说明,默认的环境就是Windows10 1903和Visual Studio 2019。
1.9 Visual Studio Code实现C语言HelloWorld
1.9.1 Visual Studio Code介绍与使用
HelloWorld是学习一门编程语言的入门程序,如果你能独立编写并运行HelloWorld,那么就意味着迈入了编程的大门了。
Visual Studio Code是微软推出的一款开源、跨平台(Windows,Ubuntu,macOS)的编辑器,这里使用它来编写C语言的源代码,当然除了编写C代码之外,还可以用来编写C++,Java,Python,Go,JavaScript,PHP程序等等。
为什么首先要使用Visual Studio Code来编写第一个C程序呢,因为Visual Studio Code只是一个编辑器,用于编写源码,并不提供编译或者解释运行程序的功能。
通过它来对比之前介绍的IDE,体验下使用IDE开发程序带来的好处,也有利于理解IDE背后的相关机制。
在使用Visual Studio Code之前首先去官网下载
然后傻瓜一键式安装,安装完成以后启动Visual Studio Code会看到启动界面。
关于Visual Studio Code的详细使用可以参考官方提供的文档。
1.9.2 编辑源文件
- 在系统的D盘下创建目录vs_codec用于存放C语言的源程序(即C代码)
- 在Visual Studio Code中将D:vs_codec目录添加到工作区的文件夹
- 在工作区D:vs_codec目录下创建源文件helloworld.c,C语言的源文件都是以.c结尾的,并编写以下内容
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
printf("Hello World Windows10 1903 & Visual Studio Code & C ");
return 0;
}
1.9.3 gcc编译和运行源程序
编译就是将源文件编译成对应平台的可执行程序,因为计算机不能识别开发人员编写的源文件内容,只能识别二进制的机器指令。
而C语言编写的源程序可以使用多种编译器来编译:Windows系统下可以安装QT或者Visual Studio 2019后编译源文件。
QT中自带了GCC编译器,以QT5.13为例,安装完QT之后,将QT自带gcc编译器默认安装路径(C:QtQt5.13.0Toolsmingw730_64in) 添加到系统的PATH环境目录下
配置PATH环境变量的目的是后面在终端输入gcc时,系统会在PATH环境变量查找gcc对应的可执行程序gcc.exe。
然后在Windows命令行的终端中输入gcc -v,看到输出gcc编译器的版本信息,就可以使用gcc编译器了。
C:Usersittim>gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=C:/Qt/Qt5.13.0/Tools/mingw730_64/bin/../libexec/gcc/x86_64-w64-mingw32/7.3.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-7.3.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw730/x86_64-730-posix-seh-rt_v5-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --enable-libstdcxx-filesystem-ts=yes --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw730/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw730/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw730/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw730/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw730/x86_64-730-posix-seh-rt_v5-rev0/mingw64/opt/include -I/c/mingw730/prerequisites/x86_64-zlib-static/include -I/c/mingw730/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw730/x86_64-730-posix-seh-rt_v5-rev0/mingw64/opt/include -I/c/mingw730/prerequisites/x86_64-zlib-static/include -I/c/mingw730/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw730/x86_64-730-posix-seh-rt_v5-rev0/mingw64/opt/include -I/c/mingw730/prerequisites/x86_64-zlib-static/include -I/c/mingw730/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw730/x86_64-730-posix-seh-rt_v5-rev0/mingw64/opt/lib -L/c/mingw730/prerequisites/x86_64-zlib-static/lib -L/c/mingw730/prerequisites/x86_64-w64-mingw32-static/lib '
Thread model: posix
gcc version 7.3.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)
在使用gcc编译器时首先需要打开Windows终端,可以使用win+r打开运行窗口,然后输入cmd即可打开终端。
然后使用d:切换到D盘中,因为cd命令只能只能在当前盘符下切换,
接着使用cd vs_codec切换到C程序的路径下,然后使用gcc helloworld.c -o helloworld.exe 编译生成可执行文件helloworld.exe,如果不使用 -o helloworld.exe,即使用gcc helloworld.c默认生成的是a.exe。后期编译时如果存在多个源文件直接在gcc 后面追加即可,多个源文件使用空格 隔开。
最后输入helloworld.exe就可以运行helloworld了。
C:Usersittim>d:
D:>cd vs_codec
D:vs_codec>gcc helloworld.c -o helloworld.exe
D:vs_codec>helloworld.exe
Hello World Windows10 1903 & Visual Studio Code & C
D:vs_codec>
1.9.4 VC编译和运行源程序
Visual Stuido 2019只需要在路径C:ProgramDataMicrosoftWindowsStart MenuProgramsVisual Studio 2019Visual Studio Tools下运行 Developer Command Prompt for VS2019,也可以直接在搜索栏中搜索Developer Command Prompt for VS 2019
然后和使用GCC编译helloworld类似,也是需要使用d:切换到D盘,然后使用cd vs_codec切换到C程序的目录。
而visual studio 提供了cl命令来编译C程序的源文件,使用方式是cl helloworld.c,默认编译链接生成helloworld.exe的同时还会编译生成helloworld.obj,此时只需要运行helloworld.exe即可。
**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.2.3
** Copyright (c) 2019 Microsoft Corporation
**********************************************************************
C:Program Files (x86)Microsoft Visual Studio2019Enterprise>d:
D:>cd vs_codec
D:vs_codec>cl helloworld.c
用于 x86 的 Microsoft (R) C/C++ 优化编译器 19.22.27905 版
版权所有(C) Microsoft Corporation。保留所有权利。
helloworld.c
Microsoft (R) Incremental Linker Version 14.22.27905.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:helloworld.exe
helloworld.obj
D:vs_codec>helloworld.exe
Hello World Windows10 1903 & Visual Studio Code & C
D:vs_codec>
除了在windows上使用gcc和VC编译之外,也可以在macOS或者Linux使用gcc编译该程序。
macOS下gcc编译运行helloworld
1.10 Visual Studio 2019集成 GitHub
在正式使用Visual Studio 2019开发C语言的程序时,可以集成GitHub插件,编译后期代码统一管理。
Github是开源的项目托管平台,在使用它之前得先创建一个账号。后续所有的C程序的源文件都会上传到GitHub,这样即使更换电脑,只需要从远程的GitHub将项目克隆到本地即可。
- 启动Visual Studio 2019
- 下载Visual Studio 的GitHub插件
点击Visual Studio菜单 扩展->管理扩展
然后点击联机,选择GitHub Extension for Visual Studio 点击下载即可。
- 安装GitHub插件
在Visual Studio 2019中下载完GitHub插件以后需要手动关闭Visual Studio 2019,然后会自动开启安装进程
此时Visual Studio会去联网下载GitHub插件,如果遇到网络原因下载超慢,可以扫描下方的二维码下载
然后关闭VisualStudio2019,进入C:Program Files (x86)Microsoft Visual Studio2019EnterpriseCommon7IDE目录下
输入cmd
此时就已经进入C:Program Files (x86)Microsoft Visual Studio2019EnterpriseCommon7IDE目录下,只需要输入VSIXInstaller.exe C:UsersittimDesktopGitHub.VisualStudio.vsix并回车后便可开始安装GitHub插件
- 连接GitHub
GitHub插件安装完成以后,重启Visual Studio 2019
首先将项目由解决方案资源管理器切换到团队资源管理器,然后点击连接GitHub
-
登录GitHub
输入用户名和密码登录GitHub
-
创建仓库
首先点击创建菜单
然后设置仓库名称、描述以及本地仓库路径、Git忽略、License
如果一切顺利,可以使用浏览器访问地址https://github.com/ittimeline/c-core 来访问项目,各位同学只需要将ittimeline替换成你们的账户即可。
1.11 Visual Studio 2019实现HelloWorld
- 新建解决方案
切换到团队资源管理器视图,在之前创建的Git仓库c-core基础上新建项目
然后选择项目模板:基于C++的空项目
然后设置项目名称、路径以及解决方案名称
- 新建筛选器
在解决方案资源管理器视图下,选中源文件,然后新建筛选器
筛选器的名称为Chapter1
- 新建源文件helloworld.c
4. 编辑源文件
#include <stdio.h>
#include<stdlib.h>
int main(int argc, char* argv[]) {
printf("Windows10 1903 & Visual Studio 2019 Hello World With C
");
system("pause");
return 0;
}
- 运行helloworld
点击本地Windows调试器,可以运行程序,也可以通过快捷键F5启动本地Windows调试器来运行程序
程序运行结果
如果想要关闭程序,可以通过快捷键Shift+F5实现。
如果运行程序时出现"若要在调试停止时自动关闭控制台"提示,可以根据提示设置在调试时停止自动关闭控制台
Visual Studio遇到printf()语句自动弹出终端输出Windows10 1903 & Visual Studio 2019 Hello World,遇到return语句关闭终端,打开终端和关闭终端时间很短,感觉程序有闪退现象。
这里可以调用stdlib.h头文件中的system函数并传递字符串参数pause让程序暂停。
- 推送代码到远程仓库
首先切换到团队资源管理器视图下,然后点击更改
然后填写提交信息,点击全部提交,此时会将代码提交到本地仓库
然后点击同步到远程仓库
推送到远程仓库
然后就可以在GitHub仓库中查看提交的内容
1.12 HelloWorld详解
1.12.1 #include预处理
在C语言中,如果想要调用系统的某个函数,必须首先使用#include包含该函数声明所在的头文件,例如helloworld程序中调用printf()函数声明,就是位于系统目录C:Program Files (x86)Windows Kits10Include10.0.18362.0ucrt下的头文件stdio.h。
如果包含的文件在当前目录下,使用#include "头文件",如果该头文件在系统目录下,则使用#include <>。而编译器查找当前目录下的头文件时如果未找到,还会去系统目录下查找对应的头文件。
#include的本质就是将包含的头文件内容全部复制到源文件中去。
如何验证这一点呢?
首先在项目c-core-foundational的头文件下新建筛选器Chapter1,并创建头文件guanglei.h
然后把之前源文件helloworld.c的源码复制到guanglei.h中
之后定义源文件guanglei.c
该源文件的内容只需要使用#include "guanglei.h" 即可运行。
但是Visual Studio 2019 解决方案(例如c-core)下每个项目(c-core-foundational)只能有一个包含main方法的源程序,否则程序运行时会出错。
这里将之前helloworld程序中的main方法改成别的名字(例如helloworld_main)即可。
然后再次运行程序,运行结果和之前的helloworld程序结果一样
#include <stdio.h>表示包含头文件stdio.h,std表示标准库,是可以移植的。也就是helloworld.c可以运行在各个操作系统下。
Windows10 1903 &CLion 2019.2
Ubuntu18.04 & CLion 2019.2
运行之前必须先安装CMake,使用sudo apt install cmake安装即可
macOS10.14 &XCode10.3
而stdio表示标准输入输出,printf()函数正是一个输出函数。
stdlib表示标准库,system()函数正是一个标准库函数,用于调用各大平台的命令。
头文件只存放了函数的定义,至于函数的实现,在对应的系统库文件中。
如果想要了解你的C程序依赖了哪些系统库,在Linux(Ubuntu)下可以使用ldd命令查看
1.12.2 main函数
main函数是C程序的入口,一个项目只能有一个main函数,否则程序运行时会提示定义多个main函数。
当程序运行时,系统自动调用main函数,程序从main函数的第一行开始执行,如果其他函数想要得到执行,那么必须被main函数直接或者间接调用。
int main(int argc, char* argv[]) {
printf("Windows10 1903 & Visual Studio 2019 Hello World
");
system("pause");
return 0;
}
-
main函数左边的int是函数的返回值,右边()的内容表示函数的参数,外部数据通过函数的参数传递到函数的内部处理。
-
{}表示函数的函数体,也就是函数执行的所有内容都包含在{}中,它是成对出现的。
-
printf函数是系统自带的函数,用于将""包含的字符串按照指定的格式输出到终端,终端可以是控制台、网页或者是文件,目前是输出到控制台。
-
表示换行,这里就是输出内容之后换行。
-
分号(;)表示一条语句结束,C语言每条执行语句都需要以分号(;)结束,如果不加上分号会发生编译错误。
-
system("pause")表示程序暂停,输入任意键后退出,如果在Visual Studio中运行C程序必须加上system("pause"),否则程序运行时遇到return语句后就直接退出。使用CLion、QT运行不需要加上system("pause")。除了system("pause")还可以使用getchar()函数实现等价的功能。
-
return 0表示将int类型的值返回给main函数的调用方(系统)并结束main函数,return语句之后的代码都不会再执行了,0表示正常结束。
在源文件function_return.c中定义了一个add方法,传递两个整数参数,返回两个整数相加的结果。并且该方法在主函数的prinf方法中被调用,用于输出两个整数相加的结果。
printf函数中的%d表示对应位置的参数按照整数输出。
#include <stdlib.h>
int add(int source,int target) {
return source + target;
printf("不可达代码
");
}
/*
return关键字和函数的调用
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
int main(int argc,char* argv[]) {
int source = 50;
int target = 100;
printf("%d加上%d的结果是%d
",source,target,add(source,target));
system("pause");
return 0;
}
程序运行结果表明add方法的return语句之后的输出语句printf("不可达代码
")并没有执行,如果想要add方法得到执行,在main方法中调用即可,调用时需要传递对应的参数。
1.13 注释
注释是用于描述程序的功能,为了便于程序后期的维护,在开发过程中应该添加适量的注释,编译器在预编译时会删除注释,所以注释的内容不会影响程序的结果。
C语言中支持的注释包含单行注释(//)和多行注释(/**/
)两种,单行注释顾名思义就是注释一行,多行注释可以注释多行,需要注意的是多行注释不能够嵌套使用,否则会发生编译错误。
增加单行注释和多行注释后的helloworld程序
#include <stdio.h>
#include<stdlib.h>
/*
我的第一个C程序
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
int main(int argc, char* argv[]) {
//快捷键F12可以查看函数定义 Ctrl+ -返回
printf("Windows10 1903 & Visual Studio 2019 Hello World With C
");
system("pause");
return 0;
}
1.14 Windows常用命令
1.14.1 Windows命令概述
主流的操作系统(Windows,Linux(Ubuntu),MacOS)及大多数应用程序都提供了基于命令行和图形化界面两种交互方式,而移动端是采用手势触控、语音等进行交互。作为普通用户来讲,图形化界面容易上手,而且交互效果更加直观。
但是作为一个程序员来讲,应该去熟悉各个操作系统的命令行的使用,因为命令行相对图形化界面而言,绝大多数场景下使用更加高效。而且图形化界面本质是对命令行的封装,能用图形化界面实现的基本都可以采用命令行实现。而且在服务器端(CentOS,RedHat)基本上是不会安装图形界面。
Windows下想要使用命令,必须首先启动控制台。
Windows系统可以使用快捷键Windows+r调出运行
后输入cmd,便可以进入Windows下的命令行终端
1.14.2 Windows常用命令
在启动Windows的终端(也称为控制台)之后,便可以运行命令了。
如果你使用Windows作为开发平台,如下的命令你也许会经常使用到。
命令名称 | 功能描述 |
---|---|
dir | 列出当前目录列表 |
cd | 切换目录(只能在根盘符(例如C盘)内切换),cd /切换到磁盘的根目录 |
md | 创建目录 |
rd | 删除空目录 |
del | 删除文件 |
type | 显示文本文件内容 |
echo | 输出文本内容 例如echo %path% 查看系统环境变量 |
ping | 检测网络,例如ping baidu.com |
notepad | 记事本 |
calc | 计算器 |
mspaint | 画图 |
explore | 文件资源管理器 |
cleanmgr | 磁盘清理 |
desk.cpl | 分辨率设置 |
powercfg.cpl | 电源设置 |
regedit | 注册表编辑器 |
msconfig | 系统配置 |
mstsc | 远程连接 |
firewall.cpl | 防火墙 |
appwiz.cpl | 添加或修改程序 |
tasklist | 查看进程列表 |
taskkill /f /im process-name.exe | 关闭指定进程 |
netstat -ano| indstr "port" |
查看端口占用 |
msinfo | 系统信息 |
sticky notes | 便签 |
ipconfig | 查看ip |
winver | 查看windows版本 |
cls | 清除屏幕内容 |
exit | 退出终端 |
在终端上使用命令时还有些快捷键,例如Tab可以补全路径,上下键可以切换之前输入的命令。*
实现模糊匹配操作,例如 del *.txt
就可以删除 指定目录的所有文本文件。
如果想要获取更多的windows命令信息,可以在终端上输入help回车后会显示每个命令的名称以及功能说明。
1.15 system函数的使用
1.5.1 使用system函数调用各大操作系统命令
system函数用于C程序中调用各大操作系统的命令和应用程序,被调用的命令和应用程序以字符串的方式作为system函数的参数传入,实现读取用户输入的命令,并执行该命令。
在windows上运行该程序时可以传入notepad,calc等等实现程序调用。
而Linux和macOS上也有自己的命令可以提供给system函数来调用。
这里编写一个交互式程序:通过借助C语言的scanf函数读取用户在终端的命令,然后调用system函数来执行对应的命令。
如果你的开发环境不是Windows10 1903和Visual Studio 2019,可以删除#define _CRT_SECURE_NO_WARNINGS
。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
/*
使用system函数执行用户输入的命令
@author tony ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
int main(int argc,char* argv[]) {
printf("请输入你要执行的命令
");
//定义数组保存用户输入的指令
char str[100] = { 0 };
//使用scanf_s函数读取用户输入的指令
scanf("%s", str);
//执行命令
system(str);
return 0;
}
Ubuntu18.04&CLion 2019 命令调用
Windows1903 &Visual Studio 2019 命令调用
因为system函数位于stdlib.h头文件中,意味着它是一个可以跨平台使用的函数,Visual Studio 2019中可以使用F12快捷键跳转到函数的定义。使用Ctrl+-快捷键实现后退。
但是各大操作系统的命令和应用程序是不相同的,例如在Windows上使用system函数传递字符串参数"notepad"时可以打开记事本,而移植到了类Unix上则无法调用记事本。
1.5.2 system函数的同步和异步
首先使用system函数打开记事本,并等待5秒后使用taskkill /f /im notepad.exe关闭记事本,
运行如下程序,发现system函数打开了记事本,但是并没有在5秒之后关闭记事本。
因为system函数默认是同步执行的,即此时当只有关闭记事本后才会接着往下执行。
#include <stdlib.h>
#include <Windows.h>
/*
打开记事本并在5秒之后就关闭
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
int main() {
//加上start使得system函数异步执行
system(" notepad");
Sleep(5000);
system("taskkill /f /im notepad.exe");
return 0;
}
如果想要system函数能够异步执行,可以在打开程序时加上start参数实现
#include <stdlib.h>
#include <Windows.h>
/*
打开记事本并在5秒之后就关闭
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
int main() {
//加上start使得system函数异步执行
system("start notepad");
Sleep(5000);
system("taskkill /f /im notepad.exe");
return 0;
}
1.16 C语言的编程流程
编写C语言的程序时,一般都会经历如下几个步骤:
- 首先需要进行需求分析,也就是具体要实现哪些功能以及梳理整体的业务流程
- 然后进行概要设计,将整体的业务流程拆分成多个功能实现
- 编码实现拆解后的功能
- 调试运行程序、如果不满足预期结果则需要解决程序的Bug
这里以打开和关闭QQ的业务场景为例,然后套用编程流程的步骤。
- 该需求就是打开QQ,然后等待若干秒后关闭QQ
- 将该功能拆解为3个函数,分别是打开QQ,关闭QQ和等待若干的秒数
- 借助system和Sleep函数实现打开关闭QQ和等待若干秒
- 调试运行程序
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>
/*
打开QQ
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
void openQQ() {
// start 不能带路径,如果有路径,首先提前进入程序所在的路径
//system(" "C:\Program Files (x86)\Tencent\QQ\QQProtect\Bin\QQProtect.exe" ");
/*
函数参数说明
第一个参数:默认为0
第二个参数 操作->Open
第三个参数 命令->这里传递的是QQ的路径,并使用了转义字符
第四五个参数 默认0,0
第六个参数 如果是0表示隐式打开,1表示默认打开,3表示最大化打开,6表示最小化打开
*/
ShellExecuteA(0, "Open", ""C:/Program Files (x86)/Tencent/QQ/Bin/QQScLauncher.exe"", 0, 0, 1);
}
/*
暂停
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
void sleep() {
int second = 0;
printf("请输入多久后关闭QQ
");
scanf("%d", &second);
printf("QQ将在%d秒后关闭
", second);
int i = 1;
while (i <= second) {
Sleep(1000);
printf("睡了%d秒
", i);
i++;
}
}
/*
关闭QQ
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
void closeQQ() {
system("start taskkill /f /im QQ.exe");
}
/*
打开并根据用户输入的时间关闭QQ
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
int main() {
openQQ();
sleep();
closeQQ();
return 0;
}
1.17 C程序的运行流程
C语言程序的运行流程一般都要经过编写源文件->预处理->编译->汇编->链接后运行这几个流程。
- 预处理
预处理主要是宏替换、包含头文件、条件编译以及删除注释等操作,预处理阶段生成文件的后缀名通常是.i。 - 编译
编译主要是将预处理好的文件生成汇编文件,编译后文件的后缀名通常是.s。 - 汇编
汇编主要是将汇编文件生成二进制文件,汇编后的文件的后缀名通常是.o。 - 链接
链接主要是将各个二进制文件、库函数、启动代码生成可执行文件。
接下来编写源程序program_running_process.c,然后结合Windows上的GCC编译器提供的各个选项实现预处理、编译、汇编、链接,关于GCC的安装和配置可以参考
Visual Studio Code实现Hello World章节的内容。
#include <stdio.h>
//定义浮点型的常量
#define PI 3.14
/*
C语言程序的运行流程
@author tony ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
int main(int argc, char* argv[]) {
printf("PI =%lf
", PI);
return 0;
}
预处理使用 gcc -E 选项即可实现,其中-o选项表示输出文件的名称
D:workspacecvisualstuido2019c-core-programmingc-core-programming-foundationalc-core-programming-foundational>gcc -E program_runing_process.c -o program_runing_process.i
预处理完成以后,生成的文件program_running_process.i的大小是54kb
当预处理完成以后,定义的常量被替换成实际的值,而#include包含的头文件内容也被复制到预处理的生成的文件中
编译通过gcc -S 选项实现
D:workspacecvisualstuido2019c-core-programmingc-core-programming-foundationalc-core-programming-foundational>gcc -S program_runing_process.i -o program_runing_process.s
编译会生成汇编文件
.file "program_runing_process.c"
.text
.def __main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.LC1:
.ascii "PI =%lf12 "
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movl %ecx, 16(%rbp)
movq %rdx, 24(%rbp)
call __main
movq .LC0(%rip), %rax
movq %rax, %rdx
movq %rdx, %xmm1
movq %rax, %rdx
leaq .LC1(%rip), %rcx
call printf
movl $0, %eax
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.section .rdata,"dr"
.align 8
.LC0:
.long 1374389535
.long 1074339512
.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0"
.def printf; .scl 2; .type 32; .endef
汇编通过gcc -c 选项实现
D:workspacecvisualstuido2019c-core-programmingc-core-programming-foundationalc-core-programming-foundational>gcc -c program_runing_process.s -o program_runing_process.o
链接gcc没有提供选项,这里只要执行gcc program_running_process.o -o program_running_process.exe就会链接生成可执行文件
D:workspacecvisualstuido2019c-core-programmingc-core-programming-foundationalc-core-programming-foundational>gcc program_runing_process.o -o program_runing_process.exe
windows下的可执行文件后缀名默认是.exe,当然gcc编译器不关心后缀名,如果你的ubuntu或者macOS下安装了gcc,也可以将C程序编译生成.exe后缀的可执行文件。
1.18 Visual Studio 2019使用技巧
1.18.1 Visual Studio 2019常用快捷键
在日常使用Visual Studio 开发中会使用到如下常用的快捷键
快捷键名称 | 功能 |
---|---|
Ctrl+k,f | 自动格式化代码 |
Ctrl+k,c | 注释代码 |
Ctrl+k,u | 取消注释代码 |
Ctrl+F5 | 不调试运行 |
Ctrl+shift+b | 编译,不运行 |
F12 | 查看函数定义 |
ctrl+- | 退出函数定义 |
F5 | 调试运行 |
F11 | 逐语句(遇到函数跳到函数内部逐语句执行) |
F10 | 逐过程 (不会进入函数内部,但是函数会被调用) |
Shift+F11 | 跳出 |
1.18.2 Visual Studio 2019调试程序
在后期编写程序时,经验不足的开发人员通常会遇到两种错误:编译错误和运行时错误,编译错误通常是编写的程序不满足编译器的语法规范,而运行时错误则是程序运行时发生的错误,想要排查程序运行时的错误,就需要使用IDE提供的调试功能。
在源文件debug.c中定义一个返回两个整数相乘的方法mul,然后在main函数中定义两个变量,并调用两个整数相乘的方法,输出计算结果
#include <stdio.h>
#include <stdlib.h>
/*
定义两个整数相乘并返回
*/
int mul(int source, int target) {
return source * target;
}
/*
调试程序
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
int main(int argc, char* argv[]) {
//定义两个变量
int source = 12;
int target = 12;
printf("source = %d target = %d
", source, target);
//调用两个整数相乘的方法,并将计算的结果保存到整数变量result中
int result = mul(source, target);
//输出两个整数相乘的结果
printf("result = %d
", result);
system("pause");
return 0;
}
在调试程序前首先需要下断点,可以使用快捷键F9下断点或者取消断点
然后使用F5调试运行程序,程序会在之前下过断点的地方暂停,此时可以在Visual Studio提供的窗口中观察变量的值
如果想要一行一行调试代码,可以使用快捷键F11,当遇到函数时(例如这里的mul函数),会进入函数的内部一行一行执行,直到该函数结束为止。
如果调试时不想进入函数的内部,可以使用快捷键F10,当程序中调用了其他函数时不会进入其他函数内部,但是函数会被调用。
如果调试时想要从一个断点跳到另外一个断点,可以使用shift+F11实现。
1.18.3 Visual Studio 2019解决C4996错误
Visual Studio 希望用户使用Visual Studio提供的非标准库函数,但是程序员希望使用标准库函数,因为标准库是可以移植的。
如果在Visual Studio中使用标准的库函数,就会引发C4996错误类似于这种提示:error C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details
.这里的strcpy是标准的库函数,而在Visual Studio中使用这个函数引发了C4996错误。
#define _CRT_SECURE_NO_WARNINGS //防止C4996错误
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
vs4996错误
error C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version 2019/08/21
*/
int main(int argc,char *argv[]) {
//定义一个字符串
char buf[32] = "";
//使用strcpy实现将字符串hi string复制到变量buf中
strcpy(buf, "hi string");
//输出字符串的内容
printf("buf = %s
",buf);
system("pause");
return 0;
}
如何解决Visual Studio中的4996错误呢?
方案1:在源文件(例如这里的vs4996.c)的第一行定义宏
#define _CRT_SECURE_NO_WARNINGS //防止4996错误
方案2:在源文件(例如这里的vs4996.c)的第一行定义如下内容:
#pragma warning(disable:4996)
1.18.4 Visual Studio 2019配置代码片段
在后期编写C程序中,需要反复使用到如下的代码片段
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
/*
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version
*/
int main(int argc,char *argv[]) {
}
这里为了减轻工作量,使用Visual Studio 2019提供的代码片段管理器来实现通过输入配置的快捷键生成模板代码。
首先自定义代码片段文件MyCCode.snippet
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>MyCCodeTemplate</Title>
<Shortcut>mcct</Shortcut>
<Description>c的标准模板代码</Description>
<Author>Microsoft Corporation</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
<SnippetType>SurroundsWith</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Code Language="cpp">
<![CDATA[#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
/*
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version
*/
int main(int argc, char *argv[])
{
system("pause");
return 0;
}]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
然后进入Visual Studio 2019 菜单 工具->代码片段管理器
选择代码片段管理器的语言为C++,然后选中My Code Snippets
把MyCCodeTemplate.snippet导入进来
导入成功之后新建任意的C程序源文件,在源文件中输入快捷键mcct就可以生成如下的代码片段
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
/*
@author liuguanglei ittimelinedotnet@gmail.com
@website ittimeline.net
@version
*/
int main(int argc, char* argv[])
{
system("pause");
return 0;
}
想要了解代码片段的更多内容,请移步官网