前言:作者接触的第一门编程语言是Python。作为一门典型的动态语言,Python的一个小小安装器为我们解决了很多环境配置上潜在的麻烦,一个自带的IDLE (Integrated Development and Learning Environment)也足够简单而完整,为快速入门上手扫除了很多障碍。更多扩展性的应用,也在官方的文档中阐述得相当详尽。
但C语言看起来完全不同。作为一门老牌的静态语言,以编译器为核心的编程环境的配置,以及编译、链接、生成等诸多步骤,相较拿一个.py文件就能跑的Python,对缺少有关经验的新手来说,确是有点头疼。作者经过诸多探索,最终决定的上手方案是Visual Studio,下面详细介绍。
Visual Studio是微软(Microsoft)为以Windows为主的平台开发的一套功能全面而强大的IDE(集成开发环境),支持C、F、VB、C/C++等多种语言的开发。
作者个人推荐使用Visual Studio 2017的最新版本(目前版本号为15.9.34)。除非还有使用C和VB两门语言的需求,或者电脑系统是2015年以前的版本,否则不推荐VS 2015以前的版本(因为会强制附带C和VB的组件,且安装时会设置系统还原点速度极慢,装好的占用还要多出几GB;另外,2015以前的版本对C/C++语言标准的支持非常不完善,非常不现代)。最新的VS 2019版也不错,但新建项目的页面相较前代做了大改,容易劝退部分依赖老教程的萌新。
Visual Studio的安装
VS的官方网站为
在这里你可以看到它的简介。
不管是2015、2017还是2019,VS都有三个主要版本可供选择:Community是免费的社区版,Professional和Enterprise是收费的专业版和企业版,对于初学者三者没有区别。如果不是专业版或企业版密钥的持有者,请放心下载社区版。
VS的下载页面为
在这个页面上只有最新版本(目前是VS 2019)可供下载。如果想下载旧版本(如2017、2015等),请访问
不过现在下载旧版本需要微软账号并注册Dev Essentials计划,而且考虑到微软这类冷门服务连接起来着实费劲,故我这里放一个VS 2017的直接下载链接(右键复制到浏览器地址栏或下载器中即可)
不确定这个链接是否永久有效,失效可私信我或自行注册Dev Essentials
下载下来的是一个名为vs_community.exe的小小安装器 (1.2MB)。双击启动之后,会进行Visual Studio Installer的安装 (几十MB)。它是VS 2017及以后特有的东西,是VS本体的安装管理器,装好并启动之后,选择Community社区版,你应该会进入一个类似这样的界面。
在上面的【工作负载】选项卡,你需要按照你的开发目标选择你需要的VS组件。实现C/C++编程必须配置的工作负载为使用C++的桌面开发。这套组件已包含生成桌面应用——即Windows上传统的的.exe程序——必备的所有环境。注意虽然它名字中只提到了C++,但对纯C同样是支持的,编写时注意规范即可(下文会讲)。
另一种与此对应的通用Windows平台 (Universal Windows Platform) 开发,目标则是新型的UWP应用程序,这是指能够上架Microsoft Store的那种软件,并不是初学者需要的,如果误勾选会浪费10GB+的硬盘空间。
在【语言包】选项卡可选择额外的安装语言
在【安装位置】选项卡可以选择软件本体、下载缓存、共享组件的安装位置。注意,你可以选择非默认的位置,但必须确保第一和第三个路径中不包含任何中文,否则很可能出现装好不能用的情况!切记切记!!
【单个组件】的配置通常无需理会。保持网络畅通,确认后,等待自动下载安装完毕即可。
安装好后的界面如下图所示
本编程环境大约5GB。基于VS Code或Sublime等搭配MinGW等编译器套件可以配置更为精简的环境,有兴趣可参见
Visual Studio中的项目和解决方案
跟一些简单的编程环境不同,VS以一个项目作为我们编写程序的基本组织单元。它包含生成一个目标程序所需的所有源代码和各种资源等,也会存储该项目编写和生成过程中的诸多中间信息和日志。而解决方案,则又是项目的容器,它允许我们将多个相关或有依赖的项目组织在一起,方便高效处理。
编程以任务为导向。下面以一个最简单的HelloWorld程序和稍复杂的连加器程序,分别展示单项目和多项目的解决方案中C语言的使用。
HelloWorld程序(单项目)
在菜单栏,选择【文件】→【新建】→【项目】(快捷键Ctrl+Shift+N),
在弹出的【新建项目】对话框中,左侧有已安装可供你选择的项目类型,我们展开【Visual C++】这一栏。要编写纯C程序,建议选择【其他】→【空项目】(避免混入不需要的C++依赖)。
如果确是要编写C++程序,【Windows桌面】→【控制台应用】也是可以的
在下面设定好你的项目名称以及位置,确保右下方为解决方案创建目录已勾选,点击确定。
项目新建成功后,一般界面右侧为解决方案资源管理器(如果找不到,点击【视图】→【解决方案资源管理器】将其唤出,快捷键Ctrl+Alt+L),在其中你可以看到我们创建的Project1项目被自动置入到了一个同名的解决方案中。
右键项目名称下的【源文件】,选择【添加】→【新建项】(快捷键Ctrl+Shift+A),
在弹出的【添加新项】对话框中,选择【Visual C++】一栏中的【代码】,你将看到C++项目支持的各种类型的代码文件。常用的C++代码格式是第一个,后缀名为.cpp,这里并没有列出纯C要用的.c格式。
我们需要在底下手动修改文件后缀名,比如把文件名称改为src1.c(啥名字都行,但注意一定要连着后缀名一块改,VS的编译器可以辨认这是纯C代码),然后确认。
你将看到【源文件】下被添加了一个C文件,双击它在主界面打开该文件,你就可以输入你的C代码了。
要生成该项目的目标程序(也就是Window上最常见的.exe程序),一般是选择菜单栏中的【生成】→【生成解决方案】
生成过程中,你将在下面输出面板中看到一些信息。如果你的程序包含错误,这里则会输出不一样的信息,详情可点击左侧错误列表查看。
通常倒数第二行->
后面的一串字符就是生成的目标程序路径,在本机上,可以直接将该路径复制到命令行运行,即
当然,在VS这样强大的IDE里显然不需要这样复制粘贴来执行程序(但新手应该知道这种没有图形界面的程序本质上是如何运行的!),我们只需选择菜单栏中的【调试】→【开始执行(不调试)】(快捷键Ctrl+F5)。
IDE将自动启动一个控制台并执行由该项目生成的程序。
注意,如果你尚未生成目标程序而直接选择执行,VS将自动替你完成生成的步骤,也就是说前面生成解决方案的步骤是可以省略的。但作为教程这里还是加以介绍,希望读者明白其中包含的基本过程。
如果你非要使用F5或者实心的运行按钮,在程序中没有断点的情况下,程序可能会在结束后自动关闭而给人一闪而过的效果。你需要找到下图所示位置禁用自动关闭。
某些情况下即使使用了Ctrl+F5正常执行,也可能遇到一闪而过的情况(VS 2017最新版不会有这种情况,建议升级),这时需要一个额外的设置。在解决方案资源管理器中,选择我们的项目(注意是那个带两个加号的项目图标,不是解决方案的图标),然后右键,选择【属性】,
在属性页左侧展开【链接器】,选择【系统】,将右侧【子系统】项的值修改为控制台。确定退出。
简易连加器程序(多项目)
还是像上一节一样创建一个项目。
但不同的是,这次我们还额外往解决方案中添加了其他几个项目。它们并没有相互依赖,只是都是我同一学习章节的内容,组织在一起比较方便。VS默认将多项目解决方案中第一个添加的作为启动项目,每次执行会固定从它开始启动。这就给我们分别调试不同的项目带来了不便,解决的方法为
右键解决方案的图标,选择【属性】,
在解决方案的属性页中,选择左侧【通用属性】→【启动项目】,再选择当前选定内容作为启动项目。
确定回到代码页,在我们当前RudiCalc项目下,快捷键Ctrl+F5执行,此时其他无关项目被自动忽略,结果如下
这个程序会自动读取当前行并转化为数字,然后与已有的数值累加起来输出,感兴趣的可以拿走源代码回去试试。
include <stdio.h>
include <ctype.h>
define MAXLINE 100
/* rudimentary calculator */
main()
{
double sum, atof(char[]);
char line[MAXLINE];
int getline(char line[], int max);
sum = 0;
while (getline(line, MAXLINE) > 0)
printf("\t%g\n", sum += atof(line));
return 0;
}
/* atof: convert string s to double */
double atof(char s[])
{
double val, power;
int i, sign;
for (i = 0; isspace(s[i]); i++)
;
sign = (s[i] == -) ? -1 : 1;
if (s[i] == + || s[i] == -)
i++;
for (val = 0.0; isdigit(s[i]); i++)
val = 10.0 * val + (s[i] - 0);
if (s[i] == .)
i++;
for (power = 1.0; isdigit(s[i]); i++) {
val = 10.0 * val + (s[i] - 0);
power *= 10.0;
}
return sign * val / power;
}
/* getline: get line into s, return length */
int getline(char s[], int lim)
{
int c, i;
i = 0;
while (--lim > 0 && (c = getchar()) != EOF && c != \n)
s[i++] = c;
if (c == \n)
s[i++] = c;
s[i] = \0;
return i;
}
本文诸多操作可能不乏繁琐稚嫩之处,欢迎大家批评指正。如有任何疑问也欢迎在此交流。