本文源自于我试图理解”extern”所做的实验。本文不讨论extern “C”的使用情况。
先看实验,再讲感想:
变量实验(1):普遍易懂1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//header.h
int a=999;
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
cout << "a=" << a << endl;
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ main.o -o main
$ ./main
a=999
变量实验(1.1):只是去掉了a的初始化,发现它会默认初始化为01
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//header.h
int a;
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
cout << "a=" << a << endl;
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ main.o -o main
$ ./main
a=0
变量实验(2):引入test.cpp1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//header.h
int a;
//test.cpp
int a = 888;
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
cout << "a=" << a << endl;
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ -c test.cpp && g++ main.o test.o -o main
test.o:(.data+0x0): multiple definition of `a'
main.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
报错说在链接阶段发现test.o和main.o重复定义了变量a,因此链接失败
变量实验(3):在test.cpp使用extern来指示外部变量a,而非重新定义变量a1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24//header.h
int a;
//test.cpp
extern int a = 888;
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
cout << "a=" << a << endl;
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ -c test.cpp && g++ main.o test.o -o main
test.cpp:4:12: warning: ‘a’ initialized and declared ‘extern’
extern int a=888;
^
test.o:(.data+0x0): multiple definition of `a'
main.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
报错说的意思是test.cpp对a进行了初始化,所以extern关键字被忽略,所以仍然是重复定义了a
变量实验(4):那就不要初始化1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//header.h
int a;
//test.cpp
extern int a;
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
cout << "a=" << a << endl;
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ -c test.cpp && g++ main.o test.o -o main
./main
a=0
成功
变量实验(5):反过来,试一下header.h中extern,而test.cpp中定义1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//header.h
extern int a;
//test.cpp
int a;
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
cout << "a=" << a << endl;
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ -c test.cpp && g++ main.o test.o -o main
./main
a=0
成功
变量试验完了,下面依葫芦画瓢,开始试验函数
函数实验(1):通俗易懂1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18//header.h
#include <iostream>
using namespace std;
void func() {cout<< "This is func() from header.h"<<endl;}
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
func();
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ main.o -o main
./main
This is func() from header.h
函数实验(2):引入test.cpp1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25//header.h
#include <iostream>
using namespace std;
void func() {cout<< "This is func() from header.h"<<endl;}
//test.cpp
#include <iostream>
using namespace std;
void func() {cout<< "This is func() from test.cpp"<<endl;}
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
func();
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ -c test.cpp && g++ main.o test.o -o main
test.o: In function `func()':
test.cpp:(.text+0x0): multiple definition of `func()'
main.o:main.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
报错说在链接阶段发现test.o和main.o重复定义了函数func(),因此链接失败
函数实验(3):在test.cpp使用extern来指示外部函数func(),而非重新定义函数func()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25//header.h
#include <iostream>
using namespace std;
void func() {cout<< "This is func() from header.h"<<endl;}
//test.cpp
#include <iostream>
using namespace std;
extern void func() {cout<< "This is func() from test.cpp"<<endl;}
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
func();
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ -c test.cpp && g++ main.o test.o -o main
test.o: In function `func()':
test.cpp:(.text+0x0): multiple definition of `func()'
main.o:main.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
报错说的意思是test.cpp还是对func()进行了实现,extern实际上没起作用,所以还是重新定义了
函数实验(4):那就不要实现函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23//header.h
#include <iostream>
using namespace std;
void func() {cout<< "This is func() from header.h"<<endl;}
//test.cpp
#include <iostream>
using namespace std;
extern void func();
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
func();
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ -c test.cpp && g++ main.o test.o -o main
$ ./main
This is func() from header.h
成功
函数实验(5):反过来,试一下header.h中extern,而test.cpp中定义1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23//header.h
#include <iostream>
using namespace std;
extern void func();
//test.cpp
#include <iostream>
using namespace std;
void func() {cout<< "This is func() from test.cpp"<<endl;};
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
func();
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ -c test.cpp && g++ main.o test.o -o main
$ /main
This is func() from test.cpp
成功
额外函数实验(1):header.h中的extern也省略掉1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23//header.h
#include <iostream>
using namespace std;
void func();
//test.cpp
#include <iostream>
using namespace std;
void func() {cout<< "This is func() from test.cpp"<<endl;};
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
func();
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ -c test.cpp && g++ main.o test.o -o main
$ /main
This is func() from test.cpp
额外函数实验(2):test.cpp中的extern也省略掉1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23//header.h
#include <iostream>
using namespace std;
void func() {cout<< "This is func() from header.h"<<endl;}
//test.cpp
#include <iostream>
using namespace std;
void func();
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
func();
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ -c test.cpp && g++ main.o test.o -o main
$ ./main
This is func() from header.h
成功
额外变量实验:header.h中的extern也省略掉1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//header.h
int a;
//test.cpp
int a = 888;
//main.cpp
#include <iostream>
#include "header.h"
using namespace std;
int main(){
cout << "a=" << a << endl;
return 0;
}
//结果如下
$ g++ -c main.cpp && g++ -c test.cpp && g++ main.o test.o -o main
test.o:(.data+0x0): multiple definition of `a'
main.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
这不就是变量实验(2)嘛!
感想
如果把test.cpp改名为header.cpp就不难理解以下:
变量实验(4)就是平常所说的: extern用来告诉编译器,变量来自外部文件
变量实验(5)就是平常所说的: 头文件中声明变量,源文件中定义变量
额外函数实验(1)就是平常所说的: 头文件中声明函数,源文件中实现函数
额外函数实验(2)说明: extern对函数可以省略,头文件也可以做实现,源文件也可以做声明
额外变量实验说明: extern对变量不能省略
为什么extern对函数可以忽略而变量不可以: 因为对变量来说,”extern int a;”是声明, “int a;”是定义并默认初始化为0;而对函数来说,”extern void func();”是声明,”void func();”还是声明
纠正这些想法
- 头文件中 “int a;” 是声明变量 -> 不,它就是定义并初始化为0
- 头文件.h和源文件.cpp在声明和定义/实现上有不同行为 -> 不,一视同仁
以上。