extern关键字总结

【本文链接】

http://www.cnblogs.com/hellogiser/p/extern.html


 【extern 变量/函数】

  extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,有2种方式:

  (1)extern告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数。

  (2)extern说明变量或者函数声明在其他的源文件里,而不用include头文件的方式来引用该函数时,链接器在各个模块中搜索这个变量或者函数来进行最终链接。

  与extern对应的关键字是 static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。


 【extern_include方案】

extern 变量和函数的声明必须在B.h文件中,其定义必须在B.cpp文件中;在A.cpp中引用的时候要include "b.h"

例如MyClass.h

 C++ Code 
1
2
3
4
5
 
#pragma once

// method 1
extern int myA; // declaration
extern int myAdd(int a, int b); // declaration

MyClass.cpp

 C++ Code 
1
2
3
4
5
6
7
8
9
 
#include "StdAfx.h"
#include "MyClass.h"

// method 1    definition
int myA = 10;
int myAdd(int a, int b)
{
    
return a + b;
}

如何在main.cpp中使用?

main.cpp

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
#include "stdafx.h"
#include <iostream>
#include "MyClass.h"  // extern int myA;  extern int myAdd(int,int)
using namespace std;

void test_extern_include()
{
    cout << myA << endl;
    cout << myAdd(
12) << endl;
}

void test_main()
{
    test_extern_include();
}

int main()
{
    test_main();
    
return 0;
}

【extern方案】

MyClass.h

extern 变量必须定义在B.h文件中,extern函数通常定义在B.cpp文件中,也可以定义在B.h文件中。在A.cpp中引用的时候要不能够添加include "b.h",但是要添加extern变量和函数声明。

MyClass.h

 C++ Code 
1
2
3
4
5
 
#pragma once

// method 2
int myB = 100// definition
int mySub(int a, int b); // declaration

MyClass.cpp

 C++ Code 
1
2
3
4
5
6
7
8
 
#include "StdAfx.h"
#include "MyClass.h"

// method 2    definition
int mySub(int a, int b)
{
    
return a - b;
}

main.cpp

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
#include "stdafx.h"
#include <iostream>
//#include "MyClass.h"  // extern int myA;  extern int myAdd(int,int)
using namespace std;

extern int myB;
extern int mySub(int a, int b);

void test_extern()
{
    cout << myB << endl;
    cout << mySub(
21) << endl;
}

void test_main()
{
    test_extern();
}

int main()
{
    test_main();
    
return 0;
}

【extern 变量】
  在一个源文件里定义了一个数组:char a[6];
  在另外一个文件里用下列语句进行了声明:extern char *a;
  请问,这样可以吗? 
  答案与分析:
  
不可以,程序运行时会告诉你非法访问。原因在于,指向类型T的指针并不等价于类型T的数组。extern char *a声明的是一个指针变量而不是字符数组,因此与实际的定义不同,从而造成运行时非法访问。应该将声明改为extern char a[ ]。

【extern 函数】

  当函数提供方单方面修改函数原型时,如果使用方不知情继续沿用原来的extern申明,这样编译时编译器不会报错。但是在运行过程中,因为少了或者多了输入参数,往往会照成系统错误,这种情况应该如何解决?

   答案与分析:

   目前业界针对这种情况的处理没有一个很完美的方案,通常的做法是提供方在自己的xxx_pub.h中提供对外部接口的声明,然后调用方include该头文件,从而省去extern这一步。以避免这种错误。


【extern “C”】

  在C++环境下使用C函数的时候,常常会出现编译器无法找到obj模块中的C函数定义,从而导致链接失败的情况,应该如何解决这种情况呢?

  答案与分析:

  C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因此会造成链接时找不到对应函数的情况,此时C函数就需要用extern “C”进行链接指定,这告诉编译器,这是一个用C写成的函数,请用C的方式来链接它们,不要生成用于链接的中间函数名。

  带extern “C”的代码在处理函数名称时,直接使用函数的名称,不采用特别的方法生成一个中间函数名称;

  而没有带extern ”C”的代码在处理函数名称时,使用特别方法生成一个中间函数名称。所以C++函数在使用C函数时,加上extern “C”才能正确的找到指定的函数。

【解决方案】

1.如果函数库没有考虑C++引用的情况,已生成库文件。我们在使用它的头文件时,可以如此使用可解决连接问题,这样时候后编译在引用cgi.h中的函数时,会按照C语言方式引用:

 C++ Code 
1
2
3
 
extern "C" {
#include "cgi.h"
}

2.如果要写一个C函数库,我们应当尽量采用如下书写方式,而避免C++用户出现1中的问题。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
// at the start of cgi.h
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

    
//============================
    // cgi source code
    //............................
    //============================
    //at the end of cgi.h
#ifdef __cplusplus
}
#endif /* __cplusplus */