新闻  |   论坛  |   博客  |   在线研讨会
C++中关于函数的extern链接性以及extern关键字
电子禅石 | 2020-02-20 13:43:07    阅读:8356   发布文章

C++中extern关键字主要有三种作用,即声明变量的链接性、函数的链接性、以及语言的链接性。所谓的链接性(linkage)是指名称如何在不同的编译单元间共享。与其相应的是作用域(scope),它描述的是名称在一个编译单元的多大范围内可见。

变量的链接性:由于C++中变量具有单定义规则(one definiton rule)(只能被定义一次),那么在同一个工程的其他文件中,如果要想使用一个已经定义的变量,只能使用声明(declaration)。一个全局变量的默认链接性是只在本文件可见,在另外一个文件中可以使用extern来声明这个变量,表示该变量已经在它处定义,从而使得该变量在“变量声明”所在的文件同样可见,达到共享的目的。

函数的链接性:默认情况下函数的链接性是外部的,即可以在文件间共享。可以使用extern来指出这一点,即该函数是在另外一个文件中定义的,不过这是可选的。但是如果用static来修饰函数的话,那么其链接性就是内部的。
如果用static修饰函数的链接性,必须同时给出函数原型以及定义。

static int private(double x);
...
static int private(double x)
{
    ...
}

  

语言的链接性:在C语言中函数是不能重载的,因此在编译后,一个函数名对应于一个翻译后的符号名,例如 test(int),对应于_test。但是C++是可以重载的,因此函数经编译器翻译后的名称会有所不同。例如会将test(int),对应于_test_i。但是可以使用extern “C”来告诉编译器不要按照C++默认的方式翻译,而使用类似于C的方式翻译。

下面通过示例来具体说下函数的链接性。
首先,函数的默认链接性是外部的。

//func.cpp
#include <iostream>

void func()
{
    std::cout<<"Location:func.cpp->func()"<<std::endl;
}

//main.cpp
#include <iostream>

void func();//or extern void func();

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

  

编译:g++ -g func.cpp main.cpp -o run
在func.cpp中定义了函数func(),要在main.cpp中使用这个函数的话,必须在main.cpp中先声明这个函数。注意这里func.cpp和main.cpp是两个独立的编译单元,通过在main.cpp中声明函数,来实现函数在文件间的共享。在编译时必须同时包含这两个cpp文件。

其次,可以使用static修饰函数,来限制函数的链接性。
如果在上面的函数中将func.cpp中的func()函数用static来修饰,同时给出函数的实现,即

static void func()
{
    std::cout<<"Location:func.cpp->func()"<<endl;
}

    1
    2
    3
    4

那么即使在main.cpp中声明函数也是无法进行编译的,可能编译错误提示如下:

/tmp/ccoMrixR.o: In function `main':
/home/project/extern/main.cpp:7: undefined reference to `func()'
collect2: ld returned 1 exit status


最后,我的一位同事给我抛出了这样的一个“疑问”:如果将func()函数放在func.h中,然后在mian.cpp中包含着func.h,那么无论是否用static修饰函数都是可行的,这不是有悖于上面的阐述吗?或者说如果这样可行的话,那么函数链接性的意义在哪儿了?

//func.h
#include <iostream>

void func()
{
    std::cout<<"Location:func.cpp->func()"<<std::endl;
}

//main.cpp
#include <iostream>
#include "func.h"
void func();

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

 
 
实际上这并不矛盾,因为当包含这个函数进行编译时,func.h和main.cpp并不是两个不同的编译单元,当然所谓函数链接性也就无从谈起。当#include “func.h”,编译main.cpp时,会将头文件进行展开,他们是同一个编译单元。
————————————————

原文链接:https://blog.csdn.net/cjf_wei/article/details/66500244

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
属于自己的技术积累分享,成为嵌入式系统研发高手。
推荐文章
最近访客