突然脑子里蹦出一个问题,为什么c++ 会有头文件怎么个东西,而诸如java,python就没有这玩意呢,是不是历史遗留问题呢。我先以函数定义来看看c++的语法吧。
我们先写两个cpp,man.cpp
中引用了add.cpp
中add函数
//add文件
int add(int x, int y)
{
return x + y;
}
//main文件
#include <iostream>
int add(int x, int y); //函数声明
int main()
{
std::cout << "The sum of 3 and 4 is " << add(1, 1) << std::endl;
return 0;
}
因为这样避免写头文件的方式如果直接用g++ main.exe
是会报错的,为了让上面正常运行我们要手动控制编译,像下面这样就能得到结果了
g++ main.cpp add.cpp -o add.exe
回到原题,我们先假设没有上面的函数声明会怎么样。首先编译器就会报错
in.cpp: In function 'int main()':
main.cpp:6:41: error: 'add' was not declared in this scope
std:cout<<"The sum of 3 and 4 is "<<add(3,4)<<std::endl;
^~~
main.cpp:6:41: note: suggested alternative: 'rand'
std:cout<<"The sum of 3 and 4 is "<<add(3,4)<<std::endl;
^~~
rand
不仅提示了没有声明函数,还贴心提示可以用rand函数代替。可以看出其实编译器非常的聪明,完全就知道这是个用到2个整数的函数。
而只编译main.cpp
的时候他又提示我们没有定义add函数。
D:\TEMP\ccEMSlyf.o:main.cpp:(.text+0x34): undefined reference to `add(int, int)'
collect2.exe: error: ld returned 1 exit status
可见c++语法规定如果你写了一个函数(define),你必须主动声明告诉c++编译器(declare)。
这样的好处可不是为了避免使用前必定义
#include<iostream>
using namespace std;
// int add(int x, int y); //函数声明
int add(int x, int y)
{
return x + y;
}
int main(){
std:cout<<"The sum of 3 and 4 is "<<add(3,4)<<std::endl;
}
是为了像上面一样把代码逻辑分开。把各个代码按照逻辑拆分成一个一个小块,方便维护管理。可以单独创建一个include 文件夹放入我们的头文件add.h
//include/add.h
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif
//src/main.cpp
#include<iostream>
#include"include/add.h"
using namespace std;
int main(){
std:cout<<"The sum of 3 and 4 is "<<add(3,4)<<std::endl;
}
add.cpp保持不变
g++ main.cpp add.cpp -o add.exe -I "../"
指定完头文件目录,你会发现结果和之前一样,但是更加的模块化了,想使用哪个模块,就加载对应模块的头文件就行了。
同时也是为了省内存。古时候不像现在动辄几g几十g的电脑。像java和python 这种解释型的语言都是运行的时候加载代码再翻译,根本不差这这点算力和内存,可几十年前那时候的计算机才十几k,甚至几k。为了省内存,搞一个声明,留一个标记给连接器对接就行,一小块一小块编译。耗时但是高效啊。