作为初学者了解 C++ 中的预处理器指令
Understanding Preprocessor Directives in C++ as a beginner
我最近开始学习C++。作为一名来自 Python 的程序员,我注意到 C++ 中的某些东西如何在 Python 中做同样的事情时有一些普遍的相似之处。
我有一个问题是理解预处理器指令。 I/O Stream 似乎是初学者程序中常用的一种。
#include
与 Python 中的 import
实际上是一回事,还是与导入“模块”完全不同?
C++ 在最新标准 (C++20) 之前没有模块。 #include
与支持模块的语言中的 import
不同。相反,它是一个源代码级包含的“header”文件。通常,headers 仅包含声明而不包含您“导入”的内容的定义。这些定义包含在链接器添加的已编译库中。
恭喜你开始学习 C++,你会遇到更多来自 Python 的问题和困惑,特别是如果你使用一些较新的标准(比如 C++11/14/17 /20).
除此之外,直接回答你的问题:
Is #include
effectively the same thing as import
in Python or is it completely different than importing "modules."
我不会谈论 C++20 模块,因为各种编译器不完全支持该功能,这不是您的问题。不幸的是,答案不是简单的是或否,而是两者兼而有之。
在 C 和 C++ 中,#include
pre-processor 指令本质上是在编译阶段之前对您 #include
的任何文件执行“copy-paste”。这允许您将大块代码分成更易于管理的文件,并且仍然引用所述文件中的代码。
在 Python/C#/Java 和其他各种语言中,您不 #include
想要访问 类 及其功能的文件,您 import
您希望引用的命名空间或模块,JIT 编译器“知道”该模块或命名空间在哪个文件中,从而允许您使用该文件中代码的功能。
Python 和 C++ 不会以相同的方式“构建”代码,因此不会以相同的方式引用部分源代码。
为了更简洁地说明这一点,请看下面的C++代码:
文件:fun.hpp
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
文件:main.cpp
#include <iostream>
#include "fun.hpp"
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
在上面的代码中,当我们#include "fun.hpp"
时,C++ pre-processor在编译之前所做的本质上是“copy-and-paste”iostream
和[=22中的代码=],因此实际编译的内容类似于以下内容:
文件:main.cpp
// #include <iostream> <- this is replaced with the whole std::iostream file
// not putting that here as it's huge.
// #include "fun.hpp" <- this is replaced with this:
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
因为这个“copy-paste”你还需要包含守卫,因为如果你做了类似下面的事情:
文件:main.cpp
#include <iostream>
#include "fun.hpp"
#include "fun.hpp"
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
此代码无法编译,因为您会收到有关重新声明的各种项目的错误,因为编译的内容如下:
文件:main.cpp
// #include <iostream> <- this is replaced with the whole std::iostream file
// not putting that here as it's huge.
// #include "fun.hpp" <- this is replaced with this:
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
// #include "fun.hpp" <- this is replaced with this:
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
为了防止双重包含和重新定义,您可以简单地执行以下操作:
文件:fun.hpp
#if !defined(FUN_HPP)
#define FUN_HPP
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
#endif // define FUN_HPP
因此,除非您将 FUN_HPP
作为 pre-processor 定义传递给编译器,否则 FUN_HPP
将 不会 被定义,直到文件被定义#include
一次,然后在任何其他时候包含它,FUN_HPP
将已经被定义,因此 pre-processor 将不会再次包含代码,从而消除了 double-definitions 的问题。
因此,就您的问题而言,C++ 中的 #include
指令有点像 Python 中的 import
指令,但主要是它们都允许文件正在放入该指令,以便更直接地从 import
或 #include
.
访问代码
我希望能增加一点清晰度。
我最近开始学习C++。作为一名来自 Python 的程序员,我注意到 C++ 中的某些东西如何在 Python 中做同样的事情时有一些普遍的相似之处。
我有一个问题是理解预处理器指令。 I/O Stream 似乎是初学者程序中常用的一种。
#include
与 Python 中的 import
实际上是一回事,还是与导入“模块”完全不同?
C++ 在最新标准 (C++20) 之前没有模块。 #include
与支持模块的语言中的 import
不同。相反,它是一个源代码级包含的“header”文件。通常,headers 仅包含声明而不包含您“导入”的内容的定义。这些定义包含在链接器添加的已编译库中。
恭喜你开始学习 C++,你会遇到更多来自 Python 的问题和困惑,特别是如果你使用一些较新的标准(比如 C++11/14/17 /20).
除此之外,直接回答你的问题:
Is
#include
effectively the same thing asimport
in Python or is it completely different than importing "modules."
我不会谈论 C++20 模块,因为各种编译器不完全支持该功能,这不是您的问题。不幸的是,答案不是简单的是或否,而是两者兼而有之。
在 C 和 C++ 中,#include
pre-processor 指令本质上是在编译阶段之前对您 #include
的任何文件执行“copy-paste”。这允许您将大块代码分成更易于管理的文件,并且仍然引用所述文件中的代码。
在 Python/C#/Java 和其他各种语言中,您不 #include
想要访问 类 及其功能的文件,您 import
您希望引用的命名空间或模块,JIT 编译器“知道”该模块或命名空间在哪个文件中,从而允许您使用该文件中代码的功能。
Python 和 C++ 不会以相同的方式“构建”代码,因此不会以相同的方式引用部分源代码。
为了更简洁地说明这一点,请看下面的C++代码:
文件:fun.hpp
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
文件:main.cpp
#include <iostream>
#include "fun.hpp"
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
在上面的代码中,当我们#include "fun.hpp"
时,C++ pre-processor在编译之前所做的本质上是“copy-and-paste”iostream
和[=22中的代码=],因此实际编译的内容类似于以下内容:
文件:main.cpp
// #include <iostream> <- this is replaced with the whole std::iostream file
// not putting that here as it's huge.
// #include "fun.hpp" <- this is replaced with this:
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
因为这个“copy-paste”你还需要包含守卫,因为如果你做了类似下面的事情:
文件:main.cpp
#include <iostream>
#include "fun.hpp"
#include "fun.hpp"
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
此代码无法编译,因为您会收到有关重新声明的各种项目的错误,因为编译的内容如下:
文件:main.cpp
// #include <iostream> <- this is replaced with the whole std::iostream file
// not putting that here as it's huge.
// #include "fun.hpp" <- this is replaced with this:
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
// #include "fun.hpp" <- this is replaced with this:
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
为了防止双重包含和重新定义,您可以简单地执行以下操作:
文件:fun.hpp
#if !defined(FUN_HPP)
#define FUN_HPP
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
#endif // define FUN_HPP
因此,除非您将 FUN_HPP
作为 pre-processor 定义传递给编译器,否则 FUN_HPP
将 不会 被定义,直到文件被定义#include
一次,然后在任何其他时候包含它,FUN_HPP
将已经被定义,因此 pre-processor 将不会再次包含代码,从而消除了 double-definitions 的问题。
因此,就您的问题而言,C++ 中的 #include
指令有点像 Python 中的 import
指令,但主要是它们都允许文件正在放入该指令,以便更直接地从 import
或 #include
.
我希望能增加一点清晰度。