首页 > 编程语言 >【C与C++的相互调用方法】

【C与C++的相互调用方法】

时间:2023-11-26 23:33:39浏览次数:29  
标签:function 调用 函数 mylib C++ 相互 main

原文:https://blog.csdn.net/qq_43899283/article/details/132343699

C与C++的相互调用方法
C与C++为什么相互调用的方式不同
C++中调用C
C中调用C++
致谢
C与C++为什么相互调用的方式不同
  C 和 C++ 之间的相互调用方式存在区别,主要是由于 C 和 C++ 语言本身的设计和特性不同。

函数调用和参数传递方式不同:C 和 C++ 在函数调用和参数传递方面有一些不同之处。C 使用标准的函数调用约定,而 C++ 在函数调用中可能包含额外的信息,如函数重载和默认参数。为了正确匹配函数签名,C++ 编译器可能会在函数名上进行名称修饰(name mangling)。
函数重载和名称修饰:C++ 支持函数重载,即可以有相同的函数名但不同的参数列表。为了在可执行文件中区分这些重载函数,C++ 编译器会在函数名中添加一些信息,以便于重载解析。这与 C 的函数名约定不同,C 中函数名是平铺的。
链接库的差异:C 和 C++ 编译器链接不同的标准库。C 编译器链接 C 标准库,而 C++ 编译器链接 C++ 标准库。由于标准库可能涉及不同的函数和数据结构,因此在链接阶段可能会有不同的处理。
编译器特性:C 和 C++ 编译器对代码的解析、优化、链接等可能会有不同的处理方式,这可能会导致在 C 和 C++ 相互调用时需要进行适当的处理。
  解决手段:为了在 C 和 C++ 之间实现相互调用,C++ 引入了 extern “C” 语法,它可以用来告诉 C++ 编译器在函数声明上使用 C 的调用约定,以便在链接阶段能够正确解析函数名。这种设计是为了在 C 和 C++ 之间实现互操作性,但由于两者的语法和特性存在差异,因此在调用方式、编译器行为和链接方式上会存在一些差异。

C++中调用C
  话不多说,直接上案例,下面是一个简单的示例,演示了如何在 C++ 代码中调用 C 函数:

首先分别创建三个文件:mylib.c、mylib.h 和 main.cpp

  mylib.c如下:

// mylib.c
#include <stdio.h>

void my_c_function() {
printf("This is a C function.\n");
}
1
2
3
4
5
6
  mylib.h如下:

// mylib.h
#ifndef MYLIB_H
#define MYLIB_H

void my_c_function();

#endif // MYLIB_H
1
2
3
4
5
6
7
  main.cpp如下:

// main.cpp
#include <iostream>

extern "C" {
// 声明 C 函数的原型
void my_c_function();
}

int main() {
std::cout << "Calling a C function from C++:" << std::endl;

// 调用 C 函数
my_c_function();

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  在这个示例中,我们使用了 #include "mylib.h" 来引入头文件,并在 C++ 中调用了 my_c_function()。这样就能正确地在 C++ 中调用 C 函数。编译步骤如下:

gcc -c mylib.c -o mylib.o # 编译 C 文件为目标文件
g++ -c main.cpp -o main.o # 编译 C++ 文件为目标文件
g++ main.o mylib.o -o app # 链接目标文件生成可执行文件
1
2
3
  编译后的文件列表如下:

  然后运行可执行文件:./app得到输出结果:

  这里可以使用objdump命令查看编译之后的中间文件mylib.o和main.o的符号表:


  可以发现,my_c_function()函数编译出的名称在mylib.o和main.o是相同。这是由于 C++ 文件中使用 extern “C” 来声明 C 调用约定,以便 C 能够正确解析函数名。
  我们来看看如果没有使用extern “C” 后的编译情况吧:

  可以发现,不使用 extern “C”, 函数 my_c_function 编译后名称变为了 (_Z13my_c_functionv) 。
  是由于在C++中,函数名在编译后会根据函数的参数类型和返回类型进行名称重整(Name Mangling),以支持函数重载等特性。这是因为C++支持函数的参数类型和个数可以不同,所以需要在编译后为每个函数生成一个唯一的名称。
  当你在C++中调用一个C函数时,如果不使用 extern “C” 声明,C++ 编译器会默认对函数名进行名称重整。而在C语言中,函数名不会被重整。
  如果你在C++中调用了一个C函数,并且没有使用 extern “C” 声明,C++ 编译器会对函数名进行名称重整,生成一个新的名字,类似 _Z13my_c_functionv 这样的名称。这个过程被称为名称重整(Name Mangling),是为了确保函数在C++中能够正确处理函数重载等特性。

C中调用C++
  下面还是来看一个简单的示例,演示了如何在 C 代码中调用 C++ 函数:

首先分别创建三个文件:mylib.cpp、mylib.h 和 main.c

  mylib.cpp如下:

// mylib.cpp
#include <iostream>

#include "mylib.h"

void my_cpp_function(int num) {
std::cout << "C++ function called with number: " << num << std::endl;
}
1
2
3
4
5
6
7
8
  mylib.h如下:

// mylib.h
#ifndef MYLIB_H
#define MYLIB_H

#ifdef __cplusplus
extern "C" {
#endif

void my_cpp_function(int num);

#ifdef __cplusplus
}
#endif

#endif // MYLIB_H

#endif // MYLIB_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  main.c如下:

// c_main.c
#include <stdio.h>

#include "mylib.h"

int main() {
printf("Calling C++ function from C\n");

// Call the C++ function
my_cpp_function(42);

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
  在这个示例中,我们使用了 #include "mylib.h" 来引入头文件,并在 main.c 中调用了 my_cpp_function()。这样就能正确地在 C 中调用 C++ 函数。编译步骤如下:

g++ -c mylib.cpp -o mylib.o # 编译 C 文件为目标文件
gcc -o main main.c mylib.o -lstdc++ # 链接目标文件生成可执行文件
1
2
注释:-lstdc++ 是用于链接 C++ 标准库的编译选项。在Linux系统中,C++ 标准库通常被命名为 libstdc++.so,使用 -lstdc++ 编译选项可以将这个库链接到可执行文件中,以便在运行时使用C++的标准库函数和功能。

  如果缺少 -lstdc++ 则会报错:

  编译后的文件列表如下:

  然后运行可执行文件:./main得到输出结果:

  这里解释一下mylib.h头文件中的 #ifdef __cplusplus:在main.c文件夹中调用mylib.h头文件,但是 C 语言中并没有 extern 这个关键字,因此,使用 #ifdef __cplusplus来充当一个译时候的阀门。
  总结一下:对于C调用C++的情况,没有 extern “C” 这样的关键字。您需要在C++代码中使用 extern “C” 来确保C++函数按照C的方式进行链接,同时在C代码中包含相应的头文件并调用这些函数。

致谢
  本文的学习参考了以下文章:C与C++如何互相调用
————————————————
版权声明:本文为CSDN博主「J.Kuchiki」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43899283/article/details/132343699

标签:function,调用,函数,mylib,C++,相互,main
From: https://www.cnblogs.com/bruce1992/p/17858219.html

相关文章

  • extern "C":实现C++和C的混合编程
    原文:https://c.biancheng.net/view/8064.html通过《C语言和C++到底有什么关系?》一节的学习,读者已经了解了C++和C语言之间的关系。简单的理解,C++就是在C语言的基础上增加了一些新特性,从大的方面讲,C++不仅支持面向过程编程,还支持面向对象编程和泛型编程;从小的方面讲,C++还......
  • 调用labview生成的dll文件中包含 labview的2维数组作为输出输出时,如何操作
    以前使用python调用labview生成的dll时,如果直接使用labview本身的二维数组,程序就会自己崩溃,也无法使用,但由于二维本质就是一维,所以用的一维加行列可以解决这个问题,绕开了这个labview二维数组的结构但是最近有研究了一下,发现可以解决这个问题,现在记录如下,首先,从网上找到了一......
  • C++U3-第2课-基础排序(二)
    上节课作业讲师视频分享链接:百度云网盘链接:https://pan.baidu.com/s/1PFBLFdX6C-9FhKXWrhDBew?pwd=l8r3提取码:l8r3本节课教学目标 插入排序概念 插入排序的代码和思路分析  插入代码详细解释【题意分析】1.从第一个元素开始,该元素可以认为已经被排序;2.取出下......
  • C++11以及17部分特性
    1//1、并发支持2//1.1、C++11内存模型:3//a.原子性(Atomicity):对于原子类型(std::atomic),其成员函数的操作是原子的,不会被其他线程中断。4//b.可见性(Visibility):对于非原子类型,通过使用互斥量或同步操作来确保共享数据的可见性,即在一个线程中对共享数据的......
  • C++ ini 实现
    首先是从https://github.com/benhoyt/inih取用的ini读取类头文件//fileini.h/*inih--simple.INIfileparserSPDX-License-Identifier:BSD-3-ClauseCopyright(C)2009-2020,BenHoytinihisreleasedundertheNewBSDlicense(seeLICENSE.txt).Gotothe......
  • Windows App SDK? C++/WinRT? 狗都不学!
    空荡荡的官网开发文档,打开直接心凉一截!只写个HelloWorld教程就敢宣布自己为“跨时代”新产品?什么“C++桌面开发者的狂欢”?什么ProjectReunion?笑死!直接让所有C++WinAPI爱好者变成真正的......
  • C++聊天集群服务器1
    ​ 先给出整个项目的结构图:​ 一、环境搭建​ 施磊的c++聊天项目。相信已经到了这部分内容就已经能够自行搭建环境了,这里主要给出搭建的具体内容,方法自行百度。下面给出环境要求。​ 1.json-cpp​ 2.muduo库​ 3.cmake​ 4.mysql二、CMake编写​ 主目录下的cmakecmake_m......
  • C/C++ 常用加密与解密算法
    计算机安全和数据隐私是现代应用程序设计中至关重要的方面。为了确保数据的机密性和完整性,常常需要使用加密和解密算法。C++是一种广泛使用的编程语言,提供了许多加密和解密算法的实现。本文将介绍一些在C++中常用的加密与解密算法,这其中包括Xor异或、BASE64、AES、MD5、SHA256、RS......
  • C++ Boost库
    《C++Boost库》1.Preface  cxmsc2.Boost库编译解压boost源码压缩目录Windows平台下,打开cmd,运行脚本bootstrap.bat脚本生成b2.exe文件boost需要通b2.exe来自动编译源码;在编译之前,需要指定一些列参数:首先可通过--help命令来查看相关的参数#展示boost里所有的库b2......
  • C++ 二叉树 家谱
    实验三树家谱文档实验说明要求完成的功能如下,测试输出如图所示:(1)输入一棵二叉树的括号表示法,完成树的构建(2)使用后序遍历递归算法遍历二叉树并输出(3)使用先序遍历非递归算法遍历二叉树并输出(4)指定家谱中的某一成员,输出其所有长辈测试例:输入:A(B(C(E,F),D(G(M,N),H))......