【C++ 语言】 C 与 C++ 兼容 ( extern "C" )(二)

简介: 【C++ 语言】 C 与 C++ 兼容 ( extern "C" )(二)

C 与 C++ 标准输出 :


C 中的标准输出 : 直接调用 printf

printf("Hello");


C++ 中的标准输出 : << 此处是 操作符重载 , cout 在 std 命名空间中 ;

cout << "Hello" << endl;


③ 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")
# TODO: 如有需要,请添加测试并安装目标。




④ CMakeLists.txt ( 总目录下 ) : 顶层的 CMake 文件, 配置全局所有子项目信息 , 这里只有一个子项目 ;


# CMakeList.txt: 顶层 CMake 项目文件,在此处执行全局配置
# 并包含子项目。
#
cmake_minimum_required (VERSION 3.8)
project ("001_CMake_1")
# 包含子项目。
add_subdirectory ("001_CMake_1")





C++ 中直接调用 C 代码 ( 无法解析的外部符号 错误 )


C++ 向下兼容 : C 中大部分代码都可以在 C++ 中直接使用 ; 但是需要做兼容处理 , 不能直接使用 ;



1. 创建测试文件 : 在上述创建的项目中 , 创建 c_extern.c 和 c_extern.h 两个文件 ;



2. c_extern.h 头文件内容 : 在头文件中定义一个带参数的方法 ;


#pragma once
//任意定义一个方法 , 该方法有若干个参数和返回值
int add(int a, int b);



3. c_extern.c 源文件内容 : 在 C 语言文件中实现上述头文件中定义的带参数的方法 ;


#include "c_extern.h"
//实现的头文件中的方法, 用于测试 C 与 C++ 兼容问题
int add(int a, int b)
{
  return 0;
}




4. CMake 配置源码 : 将 “c_extern.c” ( C文件 ) 和 “c_extern.h” ( 头文件 ) 配置到 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: 如有需要,请添加测试并安装目标。




5. 执行结果 : 点击 001_CMake_1.exe 选项 , 运行程序 ; 弹出 “生成失败 , 是否要继续调试?” 的对话框 , 此时

image.png



6. 错误提示 : 无法解析在 main 函数中调用的 add 方法 ;


严重性 代码  说明  项目  文件  行 禁止显示状态
错误  LNK1120 1 个无法解析的外部命令  ...\CMakeLists.txt  ...\001_CMake_1.exe 1 
错误  LNK2019 无法解析的外部符号 "int __cdecl add(int,int)" (?add@@YAHHH@Z),
该符号在函数 main 中被引用  
...\CMakeLists.txt  ...\001_CMake_1.cpp.obj 1


在 C++ 源码中直接调用 C 源码 , 一定会报该错误 , 下面分析产生该错误的原因 , 以及如何进行兼容处理 ;




C++ 与 C 编译结果对比


1. 创建对比文件 : 创建 下面 两个文件 , 分别是 C 代码 和 C++ 代码 ;

image.png



① c_code.c :


int add (int a, int b){
  return a+b;
}
int main(){
  return 0;
}


② c_plus_code.cpp :


int add (int a, int b){
  return a+b;
}
int main(){
  return 0;
}


C 和 C++ 中代码内容一模一样 ;



2. 获取 c_code.c 编译过程中的 机器码文件 : 使用 gcc c_code.c -o c_code.o 命令 , 可以获取编译的中间文件 , 输出到 c_code.o 文件中 ;


image.png



3. 获取 C语言文件编译后的 机器码文件中对应的符号 : 使用 nm -A c_code.o 命令 , 可以查看 c_code.o 二进制文件中的符号 ;


image.png


输出详细内容 :


root@ubuntu:~/001_c_c++# gcc c_code.c -o c_code.o
root@ubuntu:~/001_c_c++# 
root@ubuntu:~/001_c_c++# ls
c_code.c  c_code.o  c_plus_code.cpp
root@ubuntu:~/001_c_c++# 
root@ubuntu:~/001_c_c++# nm -A c_code.o
c_code.o:00000000004004d6 T add
c_code.o:0000000000601030 B __bss_start
c_code.o:0000000000601030 b completed.7594
c_code.o:0000000000601020 D __data_start
c_code.o:0000000000601020 W data_start
c_code.o:0000000000400410 t deregister_tm_clones
c_code.o:0000000000400490 t __do_global_dtors_aux
c_code.o:0000000000600e18 t __do_global_dtors_aux_fini_array_entry
c_code.o:0000000000601028 D __dso_handle
c_code.o:0000000000600e28 d _DYNAMIC
c_code.o:0000000000601030 D _edata
c_code.o:0000000000601038 B _end
c_code.o:0000000000400574 T _fini
c_code.o:00000000004004b0 t frame_dummy
c_code.o:0000000000600e10 t __frame_dummy_init_array_entry
c_code.o:00000000004006d0 r __FRAME_END__
c_code.o:0000000000601000 d _GLOBAL_OFFSET_TABLE_
c_code.o:                 w __gmon_start__
c_code.o:0000000000400584 r __GNU_EH_FRAME_HDR
c_code.o:0000000000400390 T _init
c_code.o:0000000000600e18 t __init_array_end
c_code.o:0000000000600e10 t __init_array_start
c_code.o:0000000000400580 R _IO_stdin_used
c_code.o:                 w _ITM_deregisterTMCloneTable
c_code.o:                 w _ITM_registerTMCloneTable
c_code.o:0000000000600e20 d __JCR_END__
c_code.o:0000000000600e20 d __JCR_LIST__
c_code.o:                 w _Jv_RegisterClasses
c_code.o:0000000000400570 T __libc_csu_fini
c_code.o:0000000000400500 T __libc_csu_init
c_code.o:                 U __libc_start_main@@GLIBC_2.2.5
c_code.o:00000000004004ea T main
c_code.o:0000000000400450 t register_tm_clones
c_code.o:00000000004003e0 T _start
c_code.o:0000000000601030 D __TMC_END__
root@ubuntu:~/001_c_c++#



4. 分析上述输出内容 : 由 第一行 c_code.o:00000000004004d6 T add 可以看出 , add 方法编译后的符号为 add ;



5. 获取 c_plus_code.cpp 编译过程中的 机器码文件 : 使用 gcc c_plus_code.cpp -o c_plus_code.o 命令 , 可以获取编译的中间文件 , 输出到 c_plus_code.o 文件中 ;

image.png



root@ubuntu:~/001_c_c++# gcc c_plus_code.cpp -o c_plus_code.o
root@ubuntu:~/001_c_c++# ls
c_code.c  c_code.o  c_plus_code.cpp  c_plus_code.o
root@ubuntu:~/001_c_c++# 
root@ubuntu:~/001_c_c++# nm -A c_plus_code.o
c_plus_code.o:0000000000601030 B __bss_start
c_plus_code.o:0000000000601030 b completed.7594
c_plus_code.o:0000000000601020 D __data_start
c_plus_code.o:0000000000601020 W data_start
c_plus_code.o:0000000000400410 t deregister_tm_clones
c_plus_code.o:0000000000400490 t __do_global_dtors_aux
c_plus_code.o:0000000000600e18 t __do_global_dtors_aux_fini_array_entry
c_plus_code.o:0000000000601028 D __dso_handle
c_plus_code.o:0000000000600e28 d _DYNAMIC
c_plus_code.o:0000000000601030 D _edata
c_plus_code.o:0000000000601038 B _end
c_plus_code.o:0000000000400574 T _fini
c_plus_code.o:00000000004004b0 t frame_dummy
c_plus_code.o:0000000000600e10 t __frame_dummy_init_array_entry
c_plus_code.o:00000000004006d0 r __FRAME_END__
c_plus_code.o:0000000000601000 d _GLOBAL_OFFSET_TABLE_
c_plus_code.o:                 w __gmon_start__
c_plus_code.o:0000000000400584 r __GNU_EH_FRAME_HDR
c_plus_code.o:0000000000400390 T _init
c_plus_code.o:0000000000600e18 t __init_array_end
c_plus_code.o:0000000000600e10 t __init_array_start
c_plus_code.o:0000000000400580 R _IO_stdin_used
c_plus_code.o:                 w _ITM_deregisterTMCloneTable
c_plus_code.o:                 w _ITM_registerTMCloneTable
c_plus_code.o:0000000000600e20 d __JCR_END__
c_plus_code.o:0000000000600e20 d __JCR_LIST__
c_plus_code.o:                 w _Jv_RegisterClasses
c_plus_code.o:0000000000400570 T __libc_csu_fini
c_plus_code.o:0000000000400500 T __libc_csu_init
c_plus_code.o:                 U __libc_start_main@@GLIBC_2.2.5
c_plus_code.o:00000000004004ea T main
c_plus_code.o:0000000000400450 t register_tm_clones
c_plus_code.o:00000000004003e0 T _start
c_plus_code.o:0000000000601030 D __TMC_END__
c_plus_code.o:00000000004004d6 T _Z3addii
root@ubuntu:~/001_c_c++#





6. 分析上述输出内容 : 由 最后一行 c_plus_code.o:00000000004004d6 T _Z3addii 可以看出 , add 方法编译后的符号为 _Z3addii ;



处理完毕后的文件内容 :

image.png

目录
相关文章
|
1月前
|
算法 编译器 C语言
C++语言的“Hello World”
C++语言的“Hello World”
14 0
|
1月前
|
编译器 C++
C++语言中const的用法
C++语言中const的用法
13 0
|
1月前
|
存储 编译器 C++
在C++语言中计算并打印出两个数的求和
在C++语言中计算并打印出两个数的求和
22 0
|
1月前
|
C++
C++语言中流程控制
C++语言中流程控制
14 0
|
1月前
|
程序员 API C语言
在C++语言的标准I/O库
在C++语言的标准I/O库
10 0
|
1月前
|
C++
在C++语言中return语句
在C++语言中return语句
14 0
在C++语言中return语句
|
6天前
|
缓存 编译器 API
NumPy与其他语言(如C/C++)的接口实践
【4月更文挑战第17天】本文介绍了NumPy与C/C++的接口实践,包括Python与C/C++交互基础、NumPy的C API和Cython的使用。通过案例展示了如何将C++函数与NumPy数组结合,强调了内存管理、类型匹配、错误处理和性能优化的最佳实践。掌握这些技能对于跨语言交互和集成至关重要。
|
15天前
|
程序员 C++
C++语言模板学习应用案例
C++模板实现通用代码,以适应多种数据类型。示例展示了一个计算两数之和的模板函数`add&lt;T&gt;`,可处理整数和浮点数。在`main`函数中,展示了对`add`模板的调用,分别计算整数和浮点数的和,输出结果。
11 2
|
29天前
|
Java API 开发工具
【软件设计师备考 专题 】C、C++、Java、Visual Basic、Visual C++等语言的基础知识和应用(三)
【软件设计师备考 专题 】C、C++、Java、Visual Basic、Visual C++等语言的基础知识和应用
30 0
|
29天前
|
Java 数据处理 数据库
【软件设计师备考 专题 】C、C++、Java、Visual Basic、Visual C++等语言的基础知识和应用(二)
【软件设计师备考 专题 】C、C++、Java、Visual Basic、Visual C++等语言的基础知识和应用
34 0

热门文章

最新文章