提问人:MainID 提问时间:1/21/2009 最后编辑:undur_gongorMainID 更新时间:7/10/2023 访问量:24759
如何正确使用 #include 指令?
How to use #include directive correctly?
答:
总是让我绊倒的大问题是:
这将在标头路径中搜索:
#include <stdio.h>
这会在您的本地目录中搜索:
#include "myfile.h"
您应该对 EVERY 标头执行的第二件事是:
我的文件名.h:
#ifndef MYFILENAME_H
#define MYFILENAME_H
//put code here
#endif
这种模式意味着你不能在重新定义编译中的标头时摔倒(为orsogufo向我指出这被称为“包含保护”而欢呼)。阅读一下 C 编译器如何实际编译文件(在链接之前),因为这将使 #define 的世界变得很有意义,#include 对你来说很有意义,C 编译器在解析文本时不是很聪明。(然而,C 编译器本身是另一回事)
评论
#pragma once
- 如果你有钱,请查看John Lakos的Large-Scale C++ Software Design。
- Google C++ 编码指南也有一些 OK 的东西。
- 在线查看 Sutter Herb 材料(博客)。
基本上,您需要了解哪些地方不需要包含标头,例如。转发声明。还要尝试确保包含文件一个接一个地编译,并且只在必须时才将 #includes 放入 h 文件中(例如模板)。
评论
头文件是 C 语言分离接口和实现的方式。它们分为两种类型:标准头文件和用户定义的头文件。 标准头文件(如 string.h)允许我们访问底层 C 库的功能。您应该在每个使用相关功能的 .c 文件中 #include 它。通常,这使用括号,如 #include 用户定义的头文件将函数的实现公开给其他程序员或 C 代码的其他部分。如果您已经实现了一个名为 rational.c 的模块来计算有理数,那么它应该有一个相应的 rational.h 文件用于其公共接口。每个使用该功能的文件都应该 #include rational.h,rational.c 也应该 #include 它。通常这是使用 #include“rational.h”完成的 执行 #includes 的编译部分称为 C 预处理器。它主要进行文本替换和粘贴文本。 Spence 在防止重复 #includes 的模式中是正确的,因为重复会弄乱命名空间。这是包容的基础,GNU Make给了你更多的力量,也给了你更多的麻烦。
使用 if is 在当前工作目录中
如果文件的路径包含在 C++ 包含目录中(在配置中的某个位置,例如:,则必须将路径指定为包含目录)
此外,您还可以包括 .cpp 和 .hpp(h 加号)。
有一组特定的文件可以写成这样:.对于这个特定的示例工作,您需要指定#include "yourfile.h"
yourfile.h
#include <yourfile.h>
yourfile.h
c:\mylib\yourfile.h
c:\mylib\
#include <iostream>
using namespace std;
有一个非常好的软件,它与 微软的 Visual C++ 集成 ,并显示包含路径。http://www.profactor.co.uk/includemanager.php
评论
除了其他注释之外,请记住,如果只有指针或引用,则无需在另一个标题中 #include 标题。例如:
需要标头:
#include "Y.h"
class X
{
Y y; // need header for Y
};
不需要标头:
class Y;
class X
{
Y* y; // don't need header for Y
};
//#include "Y.h" in .cpp file
第二个示例编译速度更快,依赖项更少。这在大型代码库中可能很重要。
评论
查看有关使用 和 C++ 包含 C 库的讨论。#include<filename.h>
#include<filename>
编辑:安迪·布莱斯(Andy Brice)也以更简短的方式提出了这一点。
在 null 的回答中,最重要的事情是你把 #include 放在哪里。
当您编写 #include 预处理器实际上包括您在当前文件中列出的文件的内容,包括这些文件中的任何 #includes。这显然会导致在编译时产生非常大的文件(coad 膨胀),因此您需要仔细考虑是否需要 #include。
在标准代码文件布局中,有一个包含类和函数声明的类的 .h 文件,然后是一个.cpp实现文件,您应该注意头文件中的 #includes 数。这是因为,每次对头文件进行更改时,还必须重新编译包含头文件的任何文件(即使用您的类的文件);如果标头本身有很多包含,那么使用该类的每个文件在编译时都会变得非常膨胀。
最好尽可能使用正向声明,这样可以编写方法签名等,然后在.cpp文件中 #include 相关文件,以便实际使用代码所依赖的类和结构。
//In myclass.h
class UtilClass; //Forward declaration of UtilClass - avoids having to #include untilclass.h here
class MyClass
{
MyClass();
~MyClass();
void DoSomethingWithUtils(UtilClass *util); //This will compile due to forward declaration above
};
//Then in the .cpp
#include utilclass.h
void MyClass::DoSomethingWithUtils(UtilClass *util)
{
util->DoSomething(); //This will compile, because the class definition is included locally in this .cpp file.
}
评论
#include utilclass.h
因此,您的编译器可能支持 2 个唯一的包含文件搜索路径:
非正式地,我们可以将系统称为 include 路径,将用户称为 include 路径。
#include < XX>搜索系统包含路径。
#include“XX”先搜索用户包含路径,然后搜索系统包含路径。
检查标准草案 n2521:
第 16.2 节:
2 A preprocessing directive of the form
# include < h-char-sequence> new-line
searches a sequence of implementation-defined places for a header identified
uniquely by the specified sequence between the < and > delimiters, and
causes the replacement of that directive by the entire contents of the
header. How the places are specified or the header identified is
implementation-defined.
3 A preprocessing directive of the form
# include " q-char-sequence" new-line
causes the replacement of that directive by the entire contents of the
source file identified by the specified sequence between the " " delimiters.
The named source file is searched for in an implementation-defined manner.
If this search is not supported, or if the search fails, the directive is
reprocessed as if it read
# include < h-char-sequence> new-line
with the identical contained sequence (including > characters, if any)
from the original directive.
gcc 就是一个例子
-isystem <dir> Add <dir> to the start of the system include path
-idirafter <dir> Add <dir> to the end of the system include path
-iwithprefix <dir> Add <dir> to the end of the system include path
-iquote <dir> Add <dir> to the end of the quote include path
-iwithprefixbefore <dir> Add <dir> to the end of the main include path
-I <dir> Add <dir> to the end of the main include path
要查看 gcc 的搜索位置,请执行以下操作:
g++ -v -E -xc++ /dev/null -I LOOK_IN_HERE
#include "..." search starts here:
#include <...> search starts here:
LOOK_IN_HERE
/usr/include/c++/4.0.0
/usr/include/c++/4.0.0/i686-apple-darwin9
/usr/include/c++/4.0.0/backward
/usr/local/include
/usr/lib/gcc/i686-apple-darwin9/4.0.1/include
/usr/include
/System/Library/Frameworks (framework directory)
/Library/Frameworks (framework directory)
End of search list.
那么你如何使用这些知识。
有几种思想流派。但我总是从最具体到最一般地列出我的库。
例
文件:plop.cpp
#include "plop.h"
#include "plop-used-class.h"
/// C Header Files
#include <stdio.h> // I know bad example but I drew a blank
/// C++ Header files
#include <vector>
#include <memory>
这样,如果头文件“plop-used-class.h”应该包含<vector>编译器就会发出这声音。如果我将<vector>放在顶部,则编译器将隐藏此错误。
评论
implementation-defined
implementation-defined
只是 Andy Brice 回答的附录,您还可以使用函数返回值的正向声明:
class Question;
class Answer;
class UniversityChallenge
{
...
Answer AskQuestion( Question* );
...
};
这是我不久前问过的一个问题的链接,http://bytes.com/groups/c/606466-forward-declaration-allowed 有一些很好的答案。
有没有关于如何正确使用 #include 的材料?
我强烈推荐 C++ 核心指南的 SF:源文件部分作为一个很好的起点。
我没有找到任何详细解释这种用法的 C/C++ 教科书。
关于 C++ 项目的物理组合主题的许多传统智慧可以在 John Lakos 的“大规模 C++ 软件设计”中找到。
在正式的项目中,我总是在处理它时感到困惑。
你有很好的同伴。在 C++20 模块之前,是从多个文件组成 C++ 翻译单元的唯一实用方法。它是一种简单、有限的工具,通过它,预处理器基本上将整个文件复制/粘贴到其他文件中。由此产生的编译器输入通常很大,并且工作通常从一个翻译单元重复到另一个翻译单元。#include
首先决定你是否需要它。从 https://cplusplus.com/articles/Gw6AC542/
- 如果出现以下情况,则不执行任何操作: A 根本没有引用 B
- 如果出现以下情况,则不执行任何操作: 对 B 的唯一引用是在好友声明中
- 如果出现以下情况,则向前声明 B:A 包含 B 指针或引用:B* myb;
- 如果出现以下情况,则向前声明 B:一个或多个函数具有 B 对象/指针/引用 作为 parementer,或作为返回类型:B MyFunction(B myb);
- 如果出现以下情况,则 #include“b.h”: B 是 A 的父类
- 如果出现以下情况,则 #include“b.h”:A 包含 B 对象:B myb;
下一个:为什么我无法调试?
评论