7. 总结 :
① 编译结果对比 : C 语言 add 方法编译后的符号是 add , C++ 编译后的符号是 _Z3addii , 显然二者不能互相调用 , 因此一旦在 C++ 中调用 add , 就会出现上述无法解析外部符号错误 ;
② 兼容 : 如果在 C++ 文件中调用 C 语言库 , 需要做兼容处理 ;
③ 示例 : 在 Android 中的 NDK 接口是 C++ 语言的 , 但是调用的库 如 OpenSL ES , FFMPEG 等都是 C语言的库 , 因此这里就需要用到 C 与 C++ 的兼容 ;
④ 兼容方法 : 使用 extern “C”{} 指定让大括号中的内容 以 C 语言的方式进行编译 ; 这样才能在 C++ 中找到对应的 C 语言中的函数 ; 如下示例 :
extern "C"{ #include "c_extern.c" }
编译过程 : 预处理 -> 编译 -> 汇编 -> 链接;
1. 编译预处理 : 产生 .i 后缀的预处理文件;
2. 编译操作 : 产生 .s 后缀的汇编文件;
3. 汇编操作 : 产生 .o 后缀的机器码二进制文件;
4. 链接操作 : 产生可执行文件 ;
extern “C” 在头文件中的标准用法
extern “C” 用法 :
1. 在引用处使用 : extern “C” {} 可以写在 引用 头文件的位置 , 如下 :
// 001_CMake_1.cpp: 定义应用程序的入口点。 // #include "001_CMake_1.h" extern "C" { #include "c_extern.h" } using namespace std; int main() { cout << "Hello CMake。" << endl; //调用 c_extern.h 头文件中定义的方法 //该方法定义在了 C 语言文件中 add(1, 2); return 0; }
2. 在头文件中定义 : extern “C” {} 也可以写在 头文件 中 , 一般情况下我们编写的 C 代码需要同时兼容 C 和 C++ , 因此 C 语言的头文件都进行如下定义 :
① __cplusplus 宏 : 该宏定义在 C++ 编译器中 , 如果是 C 语言编译器 , 就不会定义该宏 ;
② 使用效果 : 如果在 C++ 编译环境中 , extern “C” { 和 } 生效 , 在 C 语言编译环境中 , 不生效 ;
#pragma once
//兼容 C 与 C ++ 语言 , 在 C++ 中也可以编译 C 语言程序 // __cplusplus 是编译器中定义的 宏 //如果编译的是 C++ 代码 , 定义了__cplusplus 宏 , #ifdef __cplusplus 宏会生效 //这一组判定 extern "C" { 声明 , 是否生效 , 如果在 C++ 环境中生效 , C 语言环境中不生效 #ifdef __cplusplus extern "C" { #endif //任意定义一个方法 , 该方法有若干个参数和返回值 int add(int a, int b); //这一组判定 } 声明 , 是否生效 , 如果在 C++ 环境中生效 , C 语言环境中不生效 #ifdef __cplusplus } #endif
注意上述兼容二选一 , 不能同时使用 , 否则会报错 ;
最终的 C / C ++ 兼容 代码
最终的 C / C ++ 兼容 代码 :
1.程序结构 :
2.顶层 CMakeLists.txt : 配置多个项目 ;
# CMakeList.txt: 顶层 CMake 项目文件,在此处执行全局配置 # 并包含子项目。 # cmake_minimum_required (VERSION 3.8) project ("001_CMake_1") # 包含子项目。 add_subdirectory ("001_CMake_1")
3.项目 CMakeLists.txt : 配置单个项目中的多个源文件 ;
# CMakeList.txt: 001_CMake_1 的 CMake 项目,在此处包括源代码并定义 # 项目特定的逻辑。 # cmake_minimum_required (VERSION 3.8) # 将源代码添加到此项目的可执行文件。 add_executable (001_CMake_1 "001_CMake_1.cpp" "001_CMake_1.h" "c_extern.c" "c_extern.h") # TODO: 如有需要,请添加测试并安装目标。
4.c_extern.h :
#pragma once //兼容 C 与 C ++ 语言 , 在 C++ 中也可以编译 C 语言程序 // __cplusplus 是编译器中定义的 宏 //如果编译的是 C++ 代码 , 定义了__cplusplus 宏 , #ifdef __cplusplus 宏会生效 //这一组判定 extern "C" { 声明 , 是否生效 , 如果在 C++ 环境中生效 , C 语言环境中不生效 #ifdef __cplusplus extern "C" { #endif //任意定义一个方法 , 该方法有若干个参数和返回值 int add(int a, int b); //这一组判定 } 声明 , 是否生效 , 如果在 C++ 环境中生效 , C 语言环境中不生效 #ifdef __cplusplus } #endif
5.c_extern.c :
#include "c_extern.h" //实现的头文件中的方法, 用于测试 C 与 C++ 兼容问题 int add(int a, int b) { return 0; }
7.001_CMake_1.h :
// 001_CMake_1.h: 标准系统包含文件的包含文件 // 或项目特定的包含文件。 #pragma once #include <iostream> // TODO: 在此处引用程序需要的其他标头。
8.001_CMake_1.cpp :
// 001_CMake_1.cpp: 定义应用程序的入口点。 // #include "001_CMake_1.h" #include "c_extern.h" using namespace std; int main() { cout << "Hello CMake。" << endl; //调用 c_extern.h 头文件中定义的方法 //该方法定义在了 C 语言文件中 add(1, 2); return 0;
9.运行结果 :