链接性声明
*******************************************************************
声明外部(全局)变量或函数:
其作用是告诉编译器,这个变量或函数在别的编译单元(源文件)里定义了,也就是要把这个符号放到未解决符号表里面去(
声明外部链接)。
很简单,除了数组的声明需要稍微注意:
在一个源文件中定义数组:char a[5];
在另外一个文件正确的声明是:extern char a[];
如果声明:extern char *a; 会导致运行时错误,编译器对两者的处理是不同的:
a[0] = a[0] + 1; //a为数组
00FB13BE mov eax,dword ptr [a (0FB7138h)]
00FB13C3 add eax,1
00FB13C6 mov dword ptr [a (0FB7138h)],eax
a[0] = a[0] + 1; //a为指针
013B13BE mov eax,dword ptr [a (13B7138h)]
013B13C3 mov ecx,dword ptr [eax] //这里会导致内存访问错误,保留疑问
013B13C5 add ecx,1
013B13C8 mov edx,dword ptr [a (13B7138h)]
013B13CE mov dword ptr [edx],ecx
*******************************************************************
extern “c” 用途及写法:声明语言链接性
extern “c” 修饰的变量和函数按照C语言方式编译和链接;
主要是为了解决在编译阶段会碰到的一个问题,问题来源于C不支持重载,而C++支持重载,C++为了支持重载,引入了函数重命名的机制,两者对于函数名的编译是不一样的(C++会在
函数修饰符中加上形参类型);当在C++中调用了C编译的函数时,编译后的函数名与C的不一样,将会导致链接错误。
如何判断一段程序是由C 编译程序还是由C++编译程序编译的?
#ifdef __cplusplus
cout<<"c++"; //常常在这里加上extern “C” {}
#else
cout<<"c";
#endif
写法:
//在.h文件的头上
#ifdef __cplusplus
extern "C"{
#endif
…
//.h文件结束的地方
#ifdef __cplusplus
}
#endif /* __cplusplus */
两种用法(混合编程):
一是 在C++中引用C语言中的函数和变量, 在包含C语言头文件(假设为cExample.h)时,需进行下列处理:
一是 在C++中引用C语言中的函数和变量, 在包含C语言头文件(假设为cExample.h)时,需进行下列处理:
extern "C"
{
#include "cExample.h" //声明要用到的这些函数与变量是以C的形式编译的
}
//C++头文件 cppExample.h
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add( int x, int y ); //声明要将这些函数与变量以C的形式编译,以供C语言调用
#endif
另外,这里的一篇博文用例子说明了使用extern “c”时特别应该注意的接口是否一致:
*******************************************************************
extern const变量:
正如在const总结中所说,C++中const全局变量默认是内部链接的,
若要在多个文件中使用同一const变量(占用较大内存时,不然其实没必要),可以加extern 实现。
//cpp1
extern
const
char
s[] =
"123456"
; //变量定义,注意加extern,否则链接出错
//cpp2
extern
const
char
s[]
;
*******************************************************************
补充:C与C++的函数名修饰
编译器对C和C++这两种不同语言的相同函数执行名称修饰后结果可能不一样,因此链接程序寻址匹配函数的方法也不同;
可以用函数原型指出使用的约定:
extern
"C"
void
spiff(
int
);
extern
"C++"
void
spiff(
int
);
extern
"C++"
void
spiff(
double
,
double
);
分别对应_spiff,_spiff_i,_spiff_d_d。