# 十四、Visual Studio 与 C++

## 智能感知

如果您正在使用几乎所有的 Visual Studio 键盘映射，键入 Ctrl+J 将会调出 IntelliSense。在 Visual Studio 2012 中，智能感知应该在 C++ 中自动出现。在 Visual Studio 2010 和更早版本中，您需要手动调用它。

## 代码片段

代码片段是 Visual Studio 2012 中 C++ 的一项新功能。它们在早期版本中并不存在。如果你从未在任何语言中使用过它们，那么在 C# 项目中，开始键入“for”开始一个`for`循环；一旦智能感知选择了`for`片段，按下 Tab 键两次，观察一个`for`循环出现，并带有您可以编辑的自动字段。使用 Tab 键在字段之间切换。编辑完字段后，按回车键。光标将在循环体内传输，您所做的字段编辑显示为普通文本。

代码片段对于在枚举上切换的 switch 语句特别有用，因为它们会自动用枚举的所有成员填充 switch 语句。

## 包括库

在 C++ 中，仅仅包含一个头文件通常是不够的。通常，您需要告诉链接器链接实现头文件中声明的代码的库。为此，您需要编辑项目的属性，可在**项目**菜单中作为**项目名称属性…** 进行访问

在属性中，在**配置属性** > **链接器** > **输入**下，其中一个字段是**附加依赖项**。这是以分号分隔的**列表。LIB** 你需要链接的文件。它应该以`%(AdditionalDependencies)`结束，以便添加通过 MS Build 链接的任何附加库。

例如，对于典型的 DirectX 11 Metro 风格游戏，您可能会看到以下内容:

D2 D1 . lib；d3d 11 . lib；dxgi.libol e32 . lib；windowscodecs.libdwrite.libxaudio2.libxinput.libmfcore.libMF plat . lib；mfreadwrite.libmfu uid . lib；%(额外依赖)

如果您收到一个链接器错误，告诉您它找不到您正在使用的东西的定义，请在 MSDN 上找到该函数或类；文档将告诉您所需的头文件和库文件。

## 生成汇编代码文件

如果您想要查看您的代码编译到的汇编代码的非常接近的近似，在您的项目属性中，在**配置属性** > **C/C++** > **输出文件**下，将**汇编器输出**选项设置为除**无清单**之外的选项。

我推荐**纯汇编清单(/FA)** 或者**源代码汇编(/FAs)** 。**只包含汇编的清单**散布了足够多的行号注释，您通常可以通过与源代码文件的交叉引用来查看哪些 C++ 代码与汇编代码相对应。如果你想在一个地方看到所有的东西，而不是在你打开的任何东西之间来回切换，这可能会很有帮助。(我用记事本++)和 Visual Studio 中的 ASM 文件。

请注意，生成的程序集使用 MASM 宏(在 MSDN 可以找到它们)。如果您不知道某个特定的汇编指令是什么意思(例如 LEA)，您可以在互联网上搜索它，或者从英特尔的网站(假设 x86/Itanium)、AMD 的网站(假设 x64)或 ARM Holding 的网站(假设 ARM)下载适当的编程手册。如果你从未学过任何汇编，我绝对推荐你学(试着创建一个简单的 Windows Console 应用程序)。

理解汇编能让你更好地理解计算机内部是如何工作的。再加上计算机都是硬连线的，每次开机都开始执行相同的代码(传统上是电脑上的基本输入输出系统，尽管现在已经被 UEFI 取代)，计算机如何以及为什么快速工作的谜团开始变得模糊。

## 可怕的构建错误

如果你遇到一个看起来非常可怕的构建错误，很可能是链接器造成的。您会看到这样的消息，例如:

错误 2 错误 LNK2019:未解析的外部符号“public:_ _ this call some class::some class(wchar _ t const *)”(？？函数“void __cdecl DoSomething(void)”(？dosomesing @ @ YAXZ)D:\ vs 2010 proj \ CppSandbox \ CppSandbox \ CppSandbox . obj CppSandbox

只说它找不到你说它应该能找到的函数。在这种情况下，我将`inline`关键字添加到 CPP 文件中的构造器定义中，而不记得将该定义重新定位到头文件中。任何内联函数都需要在头部，这样链接器就不会讨厌你了。

所有那些*？？* s 和*@ @和* s 只是 C++ 在将代码编译成目标文件时如何篡改名称。名称混淆对于所讨论的编译器来说在内部是一致的，但是国际标准化组织/国际电工委员会标准并没有为名称混淆规定任何特定的模式。不同的编译器可以，而且经常会，以不同的方式破坏事物。

通常，如果您看到一个可怕的构建错误消息，很可能是链接器发出的，并且是一个未解决的符号错误。如果它说它找不到你写的东西，那么检查以确保你在头文件中的声明与定义匹配，通常是在代码文件中，但可能在头文件中，或者你忘记写它了，或者你内联声明了它，但它仍然在代码文件中。

这方面的一个例子是在前面的例子中:我的`SomeClass::SomeClass(wchar_t const *)`构造器(我总是写`const type`而不是`type const,`，所以即使是那个位也被重构)。

如果它是别人的函数或其他符号，那么很可能你没有告诉链接器。包含它的 LIB 文件。

英寸 NET 中，您只需添加对程序集的引用，就可以同时获得声明位和实际定义。在 C++ 中，声明是头文件，而定义代码(不包括内联代码，内联代码也需要在头文件中)在单独的库中。在 MSDN 库中搜索缺少的符号，并找到需要添加的库文件的名称。

C++ 构建错误看起来非常可怕，尤其是当您收到涉及模板的构建错误时。那些会让你想退出。但是不要。永远不要让可怕的错误信息获胜。首先，找出它是来自编译器(它将有一个 C####错误号格式)还是链接器(LNK####错误号格式)。

如果来自编译器，通常意味着语法错误。检查你是否忘记了头文件顶部的`#pragma`一次。另一个问题可能是您使用了标准库中的某个东西(例如，`endl`)但忘记了有一个`#using namespace std;`或在它前面加上`std::`(即`std::endl`)。

你可以两者兼而有之，但至少要做一件。有些东西可能在不同的名称空间中。例如，在 Visual Studio 2010 中，一些功能位于`stdext`命名空间中。这同样适用于您自己代码中的任何名称空间。

如果你自己运气不好，去 MSDN 输入错误信息的第一部分。你可能会发现一些有用的链接，可以链接到 MSDN 论坛上的讨论，StackOverflow 上的讨论，可能是一篇 MSDN 的文章或一篇 MSDN 的博客文章——甚至可能只是错误代码的页面本身就有你需要的提示。如果所有其他方法都失败了，在论坛网站上发布一个问题:MSDN，适当的 StackExchange 网站，或者 App Hub。

链接器错误通常是一个未解析的符号，这通常意味着您在声明和定义中不匹配，在其头外有一个内联，或者没有在项目的链接器选项中将正确的库添加到项目的额外依赖项中。如果是别的，试试上一段的策略；它们同样适用于链接器错误和编译器错误。