extern
在一个项目中必须保证函数、变量、枚举等在所有的源文件中保持一致,除非指定定义为局部的。
一个全局变量在所有的模块当中只能被声明一次,否则会出现链接错误。但是可以声明很多次,且声明必须保证类型一致。用 extern
声明时一个变量时,并不是定义一个变量,也不会为变量分配内存空间。
extern
是 c/c++ 语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数或变量可以在本模块或者其他模块中使用。通常,在模块的头文件中对本模块提供给其他模块使用的函数和全局变量以关键字 extern
声明。例如:如果模块 B 想要引用模块 A 中定义的全局变量和函数时,只包含模块 A 的头文件即可。这样,模块 B 调用模块 A 的函数时,在编译阶段,模块 B 虽然找不到该函数,但是并不会报错,它会在链接阶段中从模块 A 编译生成的目标代码中找到此函数。
与 extern
对应的关键字是 static
。被 static
修饰的全局变量或函数,只能在本模块中使用。因此,一个函数或变量只能在本模块中使用时,不能够使用 extern
修饰。
extern "C"
一个 C++ 程序中可能包含其他语言编写的部分代码,同样,C++ 编写的代码片段也可能被用在其他语言编写的代码中。但是,不同语言编写的代码相互调用是困难的,更何况用同一种语言编写,使用不同编译器进行编译的情况。因为,不同语言或者同种语言在不同编译器上编译时,在注册变量,传递参数和参数在栈上的布局上可能存在差异。
为了使它们遵守统一规则,可以使用 extern
指定一个编译和链接规约。extern "C"
指令中的 C,表示的是一种编译和链接规约,而不是一种语言。C 表示符合 C 语言的编译和链接规约的任何语言。
还要说明的是,extern "C"
指令指定的编译和链接规约,不会影响语义,只是改变编译和链接的方式。
extern "C"
,可以将它们放到 extern "C" {}
中。 FOUNDATION_EXTERN
Xcode 编译器可以识别 C 和 C++ 语言,所以在编程中也会考虑 C 和 C++ 语言的使用。
在 Xcode 中对FOUNDATION_EXTERN
的定义如下: #if defined(__cplusplus)#define FOUNDATION_EXTERN extern"C" #else #define FOUNDATION_EXTERN extern #endif
由此可以看出 FOUNDATION_EXTERN
可以兼容 extern
和 extern "C"
。
FOUNDATION_EXPORT 和 FOUNDATION_IMPORT
在 Xcode 中 FOUNDATION_EXPORT
和 FOUNDATION_IMPORT
定义如下:
#if TARGET_OS_WIN32 #if defined(NSBUILDINGFOUNDATION) #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllexport) #else #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllimport) #endif #define FOUNDATION_IMPORT FOUNDATION_EXTERN __declspec(dllimport) #else #define FOUNDATION_EXPORT FOUNDATION_EXTERN #define FOUNDATION_IMPORT FOUNDATION_EXTERN #endif
以上定义可以看出:FOUNDATION_EXPORT
和 FOUNDATION_IMPORT
这两个是用来兼容 win32 应用程序的,当然这两个宏在 iOS 编程中一般很少用到的。
FOUNDATION_EXPORT
和 FOUNDATION_IMPORT
分别来兼容 C++ 编程中的 __declspec(dllexport)
和 __declspec(dllimport)
。
- __declspec(dllexport) 声明一个导出函数,是说这个函数要从本 DLL 导出。
- __declspec(dllimport) 声明一个导入函数,是说这个函数是从别的DLL导入。
总结
如果项目中涉å及到使用 C++ 语言的编程则最好使用:FOUNDATION_EXPORT
和 FOUNDATION_IMPORT
,
FOUNDATION_EXTERN
这个就可以了。当然使用 extern
也是没有问题的。 六、参考链接