我一直想知道 msvc++ 2008 编译器是否处理同一文件的多个头文件包含,考虑这个例子:
main.cpp
#include "header.h"
#include "header.h"
编译器会多次包含该文件还是只包含一个? (我知道我可以使用#ifndef“技巧”来防止这种情况发生) 另外,如果我包含包含 10 个函数的“header.h”,但我只调用或使用 2 个函数,那么它仍然包含所有 10 个函数还是仅包含我需要的 2 个函数以及他们的所有需求?
#include
基本上是“复制粘贴”的同义词。 如果您执行相同的 #include
,则该头文件的内容将按顺序复制并粘贴两次。
关于你的第二个问题,这确实没有意义。
#include
由预处理器执行,它在编译器和链接器之前运行。 预处理器不知道也不关心头文件的内容是什么,它只是将其复制并粘贴进去。链接器也许能够消除不必要的函数,但这完全独立于预处理器。
不,编译器(或者更准确地说,预处理器)不会“自动”处理这个问题。 Visual C++ 2008 或任何其他版本中没有。而你真的不希望这样。
有两种标准方法可以解决这个问题。你应该选择其中之一。
第一个被称为包括守卫。这就是您在问题中提到的“
#ifndef
技巧”。但这肯定不是“诡计”。这是编写 C++ 代码时处理这种情况的标准习惯用法,任何其他查看源文件的程序员几乎肯定会期望在某处看到包含防护。
另一个利用 VC++ 功能(该功能也出现在其他几个 C++ 工具包中)以更容易键入的方式执行基本相同的操作。通过在头文件顶部包含行
#pragma once
,您可以指示预处理器每个翻译单元仅包含头文件一次。与包含守卫相比,这还有一些其他优点,但它们在这里并不是特别相关。
至于你的第二个问题,链接器将负责“优化”你从未在代码中调用的函数。但这是编译的最后阶段,与
#include
无关,它由预处理器处理,正如我上面提到的。
MSVC 20xx 预处理器(不是编译器——编译器永远看不到预处理器指令)在任何意义上都不会“处理”同一文件的多个#include。如果某个文件被 #included 两次,则预处理器将遵循 #includes 并包含该文件两次。 (想象一下,如果预处理器甚至考虑尝试纠正源文件的“不良”#include 行为,会出现什么样的混乱。)
由于预处理器非常仔细地遵循您的指令,因此每个 #included 文件必须保护自己不被 #included 两次。当我们在头文件顶部找到类似这样的行时,我们就会看到这种保护:
#ifndef I_WAS_ALREADY_INCLUDED // if not defined, continue with include
#define I_WAS_ALREADY_INCLUDED // but make sure I'm not included again
[ header-file real contents ]
#endif // I_WAS_ALREADY_INCLUDED
当你编写头文件时,你必须始终确保以这种方式保护它。
你为什么关心?它不会给编译器增加太多负担,因为编译器有条件地(例如,使用
#ifdef
)排除不需要编译的代码。
预处理器将包含 2 倍这些标头。这就是为什么需要头文件中的保护。 据我所知,链接器在大多数情况下会删除较新用于减少可执行文件大小的代码(函数)。