在上一讲中我们对VS2019做了简单的认识并进行了简单的编程,在介绍过程中,我们发现了几个名词:解决方案、项目、头文件、源文件。这些名词分别代表什么含义?它们之间有什么关联呢?下面我们来一起认识一下
一、认识解决方案、项目、头文件与源文件
1. 解决方案(solutions)
在VS中,解决方案是一个容器,它可以用来组织一个或多个项目、存储用户的设置以及自定义项。值得注意的是,解决方案并不是“方案”或“答案”,我们可以将它理解为一个虚拟的文件夹,它可以将一个或多个项目装在里面进行统一的管理。解决方案文件的后缀名通常为.sln和.suo。例如,我们在上一讲中创建的“C语言-小白的成长之路”就是一个解决方案,“C语言-小白的成长之路”就是这个解决方案的名称(如图1.2.1)。我们在解决方案处点击右键,在弹出的对话框中点击“在文件资源管理器中打开文件夹选项”,在弹出的窗口中就可以看到我们的解决方案文件了(如图1.2.2-1.2.3)。



2. 项目(projects)
我们实现某个功能、应用程序等,都是通过“项目”来完成的。
在这里直接引用微软官方对于“项目”的解释:
从逻辑意义上讲,项目包含编译为可执行文件、库或网站的所有文件。这些文件可以包括源代码、图标、图像、数据文件等。项目还包含程序与之通信的各种服务或组件可能需要的编译器设置和其他配置文件。
在上一讲中,我们在没有解决方案的情况下创建了项目与解决方案,下面我们将在已创建的解决方案中新建一个项目。
如图1.2.4,我们在解决方案处右键->选择“添加”->选择“新建项目”(这里要注意是“新建项目”而不是“新建项”)

在弹出的窗口中,我们选择“空项目”,点击“下一步“(如图1.2.5)。

在“配置新项目“处,我们将项目名称改为” 1.2_解决方案、项目、头文件与源文件“(如图1.2.6,注意,这里的位置一般默认为当前解决方案位置,所以不动就好)。

接着我们点击创建按钮即可完成新项目的创建,并且可以在右侧“解决方案资源管理器“中找到我们的新项目(如图1.2.7)。我们在解决方案处点击右键,在弹出的对话框中点击“在文件资源管理器中打开文件夹选项”,在弹出的窗口中就可以看到我们新建项目的文件夹了,由于我们暂时并没有在这个项目中创建任何头文件及源文件等,所以这个文件夹内只有三个XML文件(如图1.2.8-1.2.9)



在以后的很长一段学习中,我们通常要在项目中创建一个或多个头文件与源文件。
3. 头文件(header files)和源文件(source files)
在C语言以及C++程序中,通常只包含两类文件:头文件与源文件。其中头文件的扩展名为*.h,源文件的扩展名为*.c(C++为*.cpp)。
头文件:
在C语言的学习阶段,我们通常将宏定义、变量以及函数等程序元素的声明写在头文件中,在编写流程结构时,再将我们写好的头文件包含在源文件中即可。当然,如果我们写的代码量很少的情况下(比如我们学习初期没有很复杂的代码),那么将这些头文件中的代码直接写在源文件中也是可以的。
根据不同的搜索路径,头文件可以分为两种:
一种是系统头文件,这种头文件存在于编译器的类库中,是编译器预制好的,不需要我们手动进行编写,直接可以拿来使用。格式是:
#include <系统头文件名称>
例如我们在上一讲代码中的 #include <stdio.h> 就是对<stdio.h>这个系统头文件的引用。

另一种是非标准头文件,这种头文件需要我们手动进行添加并自行编写,在编写源文件时将需要头文件包含在其中。格式是:
#include “非标准头文件路径” (注意符号必须为英文状态下的符号)
下面我们来演示一下:
首先我们展开刚刚新建的项目,在头文件处右键->点击“添加”->点击“新建项”(如图1.2.11)

在弹出的“添加新项”窗口中,我们选择第二项“头文件(.h)”,然后将下面的名称改为“aa.h”(如图1.2.12,任何名称都可以,这里为了方便,但注意保留.h后缀),再点击“添加”按钮

此时我们可以看到右侧头文件目录下多出了我们刚刚创建的头文件“aa.h”

由于需要演示包含头文件的方法,这里我们将源文件一并添加进来:
同样的方法,我们在“源文件”处右键->“添加”->“新建项”(如图1.2.14),这次我们在弹出的窗口中选择第一项“C++文件(.cpp)”将下面的名称改为“bb.c”,点击“添加”按钮(如图1.2.15)


此时我们会发现在右侧源文件目录下多出了我们刚刚新建的源文件“bb.c”(如图1.2.16)

如图1.2.17,按照前文所述的方法,我们右键点击项目名称,在弹出的窗口中右键点击“在文件资源管理器中打开文件夹”,弹出的窗口即为这个项目的文件夹,与上文不同,这次文件夹中多出了我们刚刚创建的两个文件(如图1.2.18)


我们回到编译器,我们打开“aa.h”头文件,在里面输入这样一段代码(如图1.2.19):
int a;
int b;

这里需要提醒的是,按照前文所述的方法创建的头文件,编译器会自动在第一行加入#pragma once这样一行代码,这行代码的含义我们在之后的学习中会提到,在这里直接删掉即可。
接着,我们打开“bb.c”源文件,在里面输入这样一段代码(如图1.2.20):
#include <stdio.h>
#include "aa.h"
int main()
{
a = 1;
b = 2;
printf("%d\n", a + b);
return 0;
}

然后我们在右侧的解决方案资源管理器内,右键点击我们新建的项目“1.2_解决方案、项目、头文件与源文件”,在弹出的窗口中点击“设为启动项目”将其设置为启动项(如图1.2.21),如果看到项目名称的字体变粗,说明设置成功(如图1.2.22)


接着我们在上方菜单栏处依次点击“调试”->“开始执行(不调试)”即可运行我们刚刚的代码,如果输出的结果是 3 并且退出代码为0,则说明我们的代码无误。(如图1.2.23)

在上述的过程中,我们在头文件中对两个变量a,b进行了声明,并在源文件中对其进行赋值、相加并输出。在源文件的代码中#include <stdio.h>就是对系统头文件的引用,而#include "aa.h"就是对非标准头文件(即我们自己写的头文件)的引用,这里需要注意的是:
(1)在引用非标准头文件时,双引号中间要输入的是头文件的路径,而并非名称,上述示例中由于头文件和源文件在同一文件目录下,所以只需输入文件名即可,如果要引用不同文件目录下的头文件就需要输入文件路径了。
(2)在实际的项目开发中,我们一般将关联性非常强的头文件与源文件命名为相同的名称。上述示例中的头文件与源文件不同名只是为了避免误解,避免初学者误以为源文件只能包含同名的头文件。
源文件:
在C语言的学习阶段,我们通常会将函数的定义以及流程结构等写在源文件中,例如在上述的示例中,我们在源文件中实现了对a和b两个变量进行了赋值并输出二者之和这一简单的流程结构。
二、头文件与源文件之间的关系
在上述示例中,我们简单实现了头文件与源文件的编写以及包含,那么二者到底是怎么关联起来的呢?
编译期:在编译期编译器会对C语言的源文件以及源文件中包含的头文件进行编译。也就是说,编译器在编译源文件时,如果发现了#include引用的头文件,那么头文件也会连带着被编译。
连接期:连接器会将头文件与源文件经处理后生成的文件进行连接,我们可以将这一过程理解为:将头文件中的内容全部复制粘贴到源文件#include引用的位置,替换掉#include预处理指令。如图1.2.24是一个形象的图片演示(注意这里只是方便理解所以用的源代码进行演示,实际连接的是经处理过后生成的*.obj文件)
