【C++】你真的会用#include吗?

相信每个C++程序员都有这样的经历:在一个大工程中不知道是否需要#include某个头文件,又或者干脆在每一个头文件中都写上#pragma once或者使用#ifndef <标识>+#define <标识>+#endif三板斧。

或许你已经发现了,C++中的#include不同于其他语言(如JavaPythonimport),它并不那么友善,稍不留意就会导致编译错误。其实不仅如此,如果对于大工程,随意使用include将会无声无息地一点点拖慢程序的编译速度。

关于使用#include的目的

在头文件中声明函数或者类,然后在对应的cpp文件中写对应的实现,这显然是C++编程的潜规则。这时候,应该会有人跳出来说,“不这样也行啊,而且会更方便。”甚至有些“高手”说,这个#include能做的事可多了,比如用来加载配置表。

//setting.h
int a = 5;
int b = 6;
//main.cpp
#include 
using namespace::std;
int wow()
{
    #include "test.h"
    return a + b;
}

int main()
{
    std::cout<

程序的运行结果是11,可能你会相当惊讶。但如果你已经知道#include其实不过是将指定文件内容展开,然后再编译而已,那肯定能轻松理解这个赢巧奇技。当然如果是导入配置或者宏一般不会这么做,而应该是在文件开头#include

因此我们使用#include,一般是一下两个目的:

  1. 导入typedef#defineconst变量等宏配置;
  2. 使用在别的cpp文件中定义或者静态库定义的函数或者类。

include雷区:在头文件中定义并实现了函数

阅读以下程序代码:

//test.h
int func()
{
    return 0;
}
//test2.h
#include "test.h"
int func2()
{
    return func() + 1;
}
//main.cpp
#include 
#include "test.h"
#include "test2.h"
using namespace::std;
int main()
{
    std::cout<

当你点运行的时候,你很可能会惊讶地看到以下的文字:

test/test.h:1: error: redefinition of ‘int func()’

为什么会变成这样呢?其实很简单,在编译器看来,上面的代码其实等同于下面的:

//FuncA.h
int FuncA()
{
    return 100;
}
//main.cpp
#include 

int func()// ←由#include "test.h"展开得到
{
    return 0;
}

int func()// ←由#include "test2.h"展开得到,而test2.h中又有一个#include "test.h",再次展开得到
{
    return 0;
}

#include "test.h"// ←由#include "test2.h"展开得到
int func2()
{
    return func() + 1;
}

using namespace::std;
int main()
{
    std::cout<

这样,错误原因就很明显了吧,函数重定义冲突。这再次验证了C++的经典编程规范——“头文件只能声明函数,函数的定义要放到对应的cpp文件中,只能#include该头文件,而不能#includecpp源文件。”

其实不用#include也行

阅读下面的代码:

//other.cpp
int func()
{
    return 5;
}
//main.cpp
#include 
int func();//←本应该是#include "other.h"

int main()
{
    std::cout<

既然上面说了,include其实不过是将指定文件内容展开,那么我直接像上面那样把本应该出现的#include "other.h",直接替换为它的内容,不就可以少写一个文件了吗?事实证明也是可行的。如果你是使用图形界面IDE进行编程的,那么你应该理解其背后都干了些什么。实际上IDE偷偷运行了类似下面的命令:

g++ -c other.cpp
g++ -c main.cpp
g++ other.o main.o -o test
./test

g++-c选项的含义为仅执行编译操作,而不进行连接操作。当然,我在这里并不是怂恿大家以后就不写#include了,只是让大家明白背后的含义而举个不太恰当的例子,为了少些一个.h头文件而惹来一堆不直观、不方便、难编译的麻烦,这显然是愚蠢至极的做法。

最后给大家看个不使用#includehello world,其涉及的底层原理,可就不这么容易说明和理解了。

extern "C" {
    int printf(const char * _Format, ...);
}

int main()
{
    printf("hello word");
    return 0;
}

你可能感兴趣的:(C++,c语言,c++,编程语言,编译器,编译原理)