关于VS中新建项的初始后缀名的重要性
当在VisualStudio中<新建项>一个代码文件时,其后缀若是源文件(.cpp),那么即便将后缀改为头文件的后缀(.h/.hpp)并将其拖入头文件筛选器,编译器也依旧会将其当作源文件编译,导致项目在编译阶段就产生莫名其妙的Linking错误
关于VS中新建项的初始后缀名的重要性
一、埋下伏笔
- 我在Visual Studio的物理路径下(提示:按下VS顶部选项栏的
项目/显示所有文件
按钮即可查看并维护项目的物理路径)准备新建一个头文件
- 填好名称
ResourceManager
后,我手快直接便点了添加(A)
按钮,文件便创建成功了,我连忙将后缀改回.hpp
(由于VS新建项无法选择.hpp
后缀,所以我一般都是先新建.h
文件然后将其改为.hpp
,并删除其默认添加的#pragma once
并改为#ifndef
形式头文件守卫,我喜欢这样) - 离开物理路径,我发现这个
ResourceManager.hpp
乖巧地躺在源文件
的筛选器目录下,我并没有在意,将其拖入头文件
筛选器下,此时的项目结构如下(可以看到这个小可爱的左侧图标赫然显示的是头文件类型,气死我了)
- 然后我开始了编程,最终实现完成了该类,其结构如下(注意函数名,对比后文的报错信息)
二、问题发作
- 然后我运行包含程序入口点main函数的
Main.cpp
源文件(该文件实际上包含了ResourceManager.hpp
,记住这一点)
- 然后就出现了下面显示的链接错误(注意错误函数的名称),即Linker在链接各编译单元
.obj
时发生了函数的重定义错误,而产生错误的源头即源于ResourceManager
类的成员方法
- 我反复检查
ResourceManager.hpp
内的头文件守卫,完全没有任何问题,根本不可能存在重定义的问题,我百思不得其解
1
2
3
4
5
6
#ifndef _RESOURCE_MANAGER_HPP_
#define _RESOURCE_MANAGER_HPP_
...
#endif
三、发现端倪
- 我们知道普通头文件是无法使用
Ctrl + F7
进行单文件编译的,如下图的红框内图标所示
- 然后我们看
ResourceManager.hpp
文件
- 气笑了,问题就出在这里,我将该文件删除,新建项一个
.h
头文件并改后缀为.hpp
后,将内容转移至新文件内,编译Main.cpp
,没有报任何的链接错误
四、问题原因
- 推送到远程仓库后我查看代码差异,果不其然,此问题与
.vcxproj
后缀的文件有关,关于此文件的结构和作用请自行谷歌
- 上文我们也可以看到,筛选器内文件类型的图标是会骗人
- 可见C++的脚本文件的后缀名的意义大抵仅仅是一种习惯性的规范,理论上无论是什么后缀名,我们都可以规定编译器该如何对其进行处理(类似地,VSCode中就可以通过修改
launch.json
、tasks.json
文件对编译规则进行规定)
本文由作者按照 CC BY-NC-SA 4.0 进行授权