extern 用法整理

来源:互联网 发布:手机改编歌词软件 编辑:程序博客网 时间:2024/04/25 23:35

刚开通博客,把原来自己写的一个关于extern的用法整理贴出来供大家参考!有些是copy网上的文章,当然也有不少是自己写的啦!

这几天忙着考试,欢迎大家指证,不过这几天在复习,准备无聊的期末考试就暂时不会回了!以后会更正过来!

 

一、      用于变量前

1.        在一个文件内声明外部变量,主要是使外部变量的作用范围扩大。

示例:

void main()

{

    extern a;  //引用之前声明外部变量

    printf(“%d/n”,a);

}

 

int a = 9;

2.         在多个文件的程序中声明外部变量,使其他文件中的变量可以在本程序中使用。

File1

int A = 9;

void main()

{
}

 

File2

extern a;//声明a在别个文件中定义

void fun()

{

printf(“%d/n”,a);

}

二、      用于函数前面

 如果函数的声明中带有关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它作用。所以可以替代include “*.h”的作用。究其原因,函数本身是外部的,所以extern仅仅是声明一下而已。

三、      externc”的用法

1.         用法原因解析

C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:

void foo( int x, int y );

该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float

看一段程序:

int i;

int func(int i)

{

return 0;
}

void main()
{

}

C语言编译完后func变成_func,main变成_main;C++编译完后func变成了?func@@YAHH@ZC++中的这种看似复杂的命名规则是为C++中的函数重载,参数检查等特性服务的。

2.       不同编译方式下的函数调用

   如果C语言或者C++的函数调用,对于外部的函数通过头文件或者extern声明都可以实现在本文件中的使用,如果是CC++的混合编程,这个时候extern “c” 则派上用场了。

//A.CPP

void func();  

void main()

{

    func();

}

//B.C

void func()

{

}

AB分别编译都没有问题,但在链接时则会出问题,原因就在于不同的编译方式产生的冲突,对于文件A,是按照C++的方式进行编译的,其中的func()调用被编译成了?func1@@YAXXZ 如果B文件也是按照C++方式编译的,那么B中的func函数名也会被编译器改成?func1@@YAXXZ,这样的话,就没有任何问题。但是现在对B文件,是按照C方式编译的,B中的func函数名被改成了_func,这样一来,A中的call ?func1@@YAXXZ这个函数调用就没有了着落,因为在链接器看来,B文件中没有名为?func1@@YAXXZ的函数。事实是,我们编程者知道,B文件中有A中调用的func函数的定义,只不过它是按照C方式编译的,故它的名字被改成了_func。因而,我们需要通过某种方式告诉编译器:“B中定义的函数func()经编译后命名成了_func,而不是?func1@@YAXXZ,你必须通过call _func来调用它,而不是call ?func1@@YAXXZ。”简单的说,就是告诉编译器,调用的func()函数是以C方式编译的,fun();语句必须被编译成call _func;而不是call ?func1@@YAXXZ

    所以我们可以通过extern C”来解决问题。只需要在A前面加上

extern “C”

{

   void fun();

}

同样的extern c”也可以修饰变量。

A.cpp

extern "C"

{

   int a;

}

 

void main()

{

    a = 89;

    printf("%d",a);

}

B.c

int a = 9;

3.   extern “c”深度剖析

这个从一个面试题说起,什么标准头文件都有类似以下的结构?

#ifndef __INCvxWorksh
#define __INCvxWorksh
#ifdef __cplusplus
extern "C" {
#endif
/*...*/
#ifdef __cplusplus
}
#endif
#endif /* __INCvxWorksh */

 显然头文件中#ifndef __INCvxWorksh#define __INCvxWorksh#endif” 的作用是防止该头文件被重复引用。那么剩下的又是什么?

    __cplusplusC++程序中预先定义的宏只要是C++的编译器,都隐含定义了__cplusplus宏。如果此时C++程序的话,extern C{ 就有效,然后是正文中声明的函数,后面的}也会有效。如果是C语言程序的话则extern C”未被声明,正文相当普通的函数声明。

 

 

 

原创粉丝点击