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

来源:互联网 发布:sql instr函数 编辑:程序博客网 时间:2024/06/06 01:59

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

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

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

 

关于使用#include的目的

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

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

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

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

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

 

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

阅读以下程序代码:

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

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

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

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

//FuncA.hint FuncA(){    return 100;}
//main.cpp#include <iostream>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<<func()<<std::endl;    std::cout<<func2()<<std::endl;    return 0;}

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

 

其实不用#include也行

阅读下面的代码:

//other.cppint func(){    return 5;}
//main.cpp#include <iostream>int func();//←本应该是#include "other.h"int main(){    std::cout<<func();    return 0;}

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

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

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

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

extern "C" {    int printf(const char * _Format, ...);}int main(){    printf("hello word");    return 0;}
原创粉丝点击