现在的位置: 首页 > 综合 > 正文

extern深度解析

2018年04月03日 ⁄ 综合 ⁄ 共 1965字 ⁄ 字号 评论关闭

C语言中extern用法:

    对于全局变量来说,extern关键字可以在一个模块中使用在另一个模块中定义的全局变量.只要extern声明一下就好,但是变量只能定义一次,不然链接的时候会报错.(现代编译器一般采用按文件编译的方式,因此在编译时,各个文件中定义的全局变量是互相不透明的。也就是说,在编译时,全局变量的可见域限制在文件内部。但是到了链接阶段,要将各个文件的内容“合为一体”,因此,如果某些文件中定义的全局变量名相同的话,在这个时候就会出现错误,也就是上面提示的重复定义的错误。因此,各个文件中定义的全局变量名不可相同。这个特性也是我们使用extern的前提)

 对于函数来讲extern的用法和全局变量是一样的,但是,我们更习惯于在头文件中声明其他模块可能用到的全局变量和函数,区别在于全局变量前一般加extern,而函数则可加可不加.(值得注意的是头文件可能包含在多个源文件中,所以不应该有变量或者函数的定义,但是也有三个例外:头文件可以定义类,值在编译时就已经知道的const对象和inline函数)

附:const对象只存在于定义的那个文件中,不能被其他文件访问,同样可以指定const对象为extern,就可以在整个程序中访问const对象.

C++中extern用法:

作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:void
foo( int x, int y );该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。
未加extern "C"声明时的连接方式

假设在C++中,模块A的头文件如下:

// 模块A头文件 moduleA.h

#ifndef MODULE_A_H

#define MODULE_A_H

     int foo( int x, int y );

#endif

在模块B中引用该函数:

// 模块B实现文件 moduleB.cpp

#i nclude "moduleA.h"

foo(2,3);

实际上,在连接阶段,连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号。

加extern "C"声明后的编译和连接方式

加extern "C"声明后,模块A的头文件变为:

// 模块A头文件 moduleA.h

#ifndef MODULE_A_H

#define MODULE_A_H

     extern "C" int foo( int x, int y );

#endif

在模块B的实现文件中仍然调用foo( 2,3 ),其结果是:

(1)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式;

(2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。

如果在模块A中函数声明了foo为extern "C"类型,而模块B中包含的是extern int foo( int x, int y ) ,则模块B找不到模块A中的函数;反之亦然。

结论:extern
"C"修饰的变量和函数是按照C语言方式编译和连接的

extern "C"的惯用法

(1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:

extern "C"

{

#i nclude "cExample.h"

}

而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。

(2)在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern "C"的该头文件,应该仅将C文件中将C++中定义的extern
"C"函数声明为extern类型。

//C++头文件 cppExample.h

#ifndef CPP_EXAMPLE_H

#define CPP_EXAMPLE_H

extern "C" int add( int x, int y );

#endif

//C++实现文件 cppExample.cpp

#i nclude "cppExample.h"

int add( int x, int y )

{

        return x + y;

}

/* C实现文件 cFile.c

/* 这样会编译出错:#i nclude "cExample.h" ,所以只能在.c文件中使用extern来声明*/

extern int add( int x, int y );

int main( int argc, char* argv[] )

{

        add( 2, 3 );   

        return 0;

}

特别说明:如果使用函数指针的方法,那么C/C++之间的函数编译后差异化可以无视,即可不使用extern “C”。


抱歉!评论已关闭.