当前位置:   article > 正文

C语言如何封装CPP代码的接口_hex code cpp 封装

hex code cpp 封装

为什么要用C语言封装CPP代码?

C++不是兼容C语言的吗?

是的,如果你只是自己开发程序,只用一种语言的话,就没有必要进行封装。如果你开发的是一个C++的.so库,你希望将这个库提供给其他语言使用的话,就涉及到不同语言的相互调用,大家都知道C语言的库是最容易与其他语言交互的。

比如mysql是用C++编写的,但还会提供C语言的调用接口(.h头文件),但是这个头文件与C++所用的头文件是不一样的,因为C语言处理不 了Class这些东西。

这个文章我们只讲如何在C语言中调用C++代码。

基本方法是,写一个 wrapper文件,把 C++类封装起来,对外只提供C语言的接口,和 C++相关的实现在 wrapper的实现文件里实现一遍。

如何封装。

提供一个C语言专用的头文件,里面只提供完成程序功能最基本的C语言类型指针和函数,所有的功能都通过此头文件对应的函数实现。

所有的定义放在extern "C" { }代码块中包裹起来。

看下面的示例:

假定有一个类定义 ,是用C++定义的。

apple.h

  1. #ifndef __APPLE_H__
  2. #define __APPLE_H__
  3. enum class LogLevel {
  4. Trace /// Most detailed output
  5. ,Debug
  6. ,Info
  7. ,Warn
  8. ,Error
  9. ,Fatal /// Least detailed output
  10. ,Current /// no-op, value indicates current level should be retained
  11. };
  12. class Apple
  13. {
  14. public:
  15. Apple();
  16. int GetColor(void);
  17. void SetColor(int color);
  18. private:
  19. int m_nColor;
  20. };
  21. #endif

apple.cpp

  1. #include "apple.h"
  2. Apple::Apple() : m_nColor(0)
  3. {
  4. }
  5. void Apple::SetColor(int color)
  6. {
  7. m_nColor = color;
  8. }
  9. int Apple::GetColor(void)
  10. {
  11. return m_nColor;
  12. }

 此时如果直接用C++写main函数是这样的:

  1. #include "apple.h"
  2. #include <iostream>
  3. // main for cpp
  4. int main(void)
  5. {
  6. Apple a;
  7. a.SetColor(1);
  8. printf("color = %d\n", a.GetColor());
  9. return 0;
  10. }

编译生成mainpp程序

  1. g++ -g -c apple.cpp -o apple.o
  2. g++ -g main.cpp -o mainpp apple.o

但是如果将apple.cpp编译成一个库提供给C语言开发者,C语言肯定是无法调用 的。

所以就要有一个wrapper。

apple_c.h

  1. #ifndef _APPLE_C_H_
  2. #define _APPLE_C_H_
  3. #if defined _WIN32 || defined WIN32 || defined _WINDOWS || defined __CYGWIN__
  4. #ifdef _DLL
  5. #ifdef __GNUC__
  6. #define DLL_PUBLIC __attribute__ ((dllexport))
  7. #else
  8. #define DLL_PUBLIC __declspec(dllexport)
  9. #endif
  10. #else
  11. #ifdef __GNUC__
  12. #define DLL_PUBLIC __attribute__ ((dllimport))
  13. #else
  14. #define DLL_PUBLIC __declspec(dllimport)
  15. #endif
  16. #endif
  17. #define DLL_LOCAL
  18. #else
  19. #if __GNUC__ >= 4
  20. #define DLL_PUBLIC __attribute__ ((visibility ("default")))
  21. #define DLL_LOCAL __attribute__ ((visibility ("hidden")))
  22. #else
  23. #define DLL_PUBLIC
  24. #define DLL_LOCAL
  25. #endif
  26. #endif
  27. #ifdef __cplusplus
  28. extern "C" {
  29. #endif
  30. typedef enum {
  31. LogLevelTrace = 0, /// Most detailed output
  32. LogLevelDebug,
  33. LogLevelInfo,
  34. LogLevelWarn,
  35. LogLevelError,
  36. LogLevelFatal /// Least detailed output
  37. } AppLogLevel;
  38. typedef void* ApplePtr; //指针类型定义
  39. DLL_PUBLIC ApplePtr GetInstance(void);
  40. DLL_PUBLIC void ReleaseInstance(ApplePtr ptr);
  41. DLL_PUBLIC void SetColor(ApplePtr ptr, int color);
  42. DLL_PUBLIC int GetColor(ApplePtr ptr);
  43. #ifdef __cplusplus
  44. };
  45. #endif
  46. #endif

apple_c.cpp

  1. #include "apple_c.h"
  2. #include "apple.h"
  3. #include <exception>
  4. #include <iostream>
  5. #ifdef __cplusplus
  6. extern "C" {
  7. #endif
  8. DLL_PUBLIC ApplePtr GetInstance(void)
  9. {
  10. return new Apple;
  11. }
  12. DLL_PUBLIC void ReleaseInstance(ApplePtr ptr)
  13. {
  14. try {
  15. auto *client = static_cast<Apple*>(ptr);
  16. delete client;
  17. ptr = nullptr;
  18. } catch (std::exception &e) {
  19. std::cout<< e.what() << std::endl;
  20. }
  21. }
  22. DLL_PUBLIC void SetColor(ApplePtr ptr, int color)
  23. {
  24. if (ptr == nullptr) {
  25. return ;
  26. }
  27. auto *pApple = static_cast<Apple*>(ptr);
  28. pApple->SetColor(color);
  29. }
  30. DLL_PUBLIC int GetColor(ApplePtr ptr)
  31. {
  32. if (ptr == nullptr) {
  33. return -1;
  34. }
  35. auto *pApple = static_cast<Apple*>(ptr);
  36. return pApple->GetColor();
  37. }
  38. #ifdef __cplusplus
  39. };
  40. #endif

main.c的写法:

  1. #include "apple_c.h"
  2. #include <stdio.h>
  3. int main(void)
  4. {
  5. ApplePtr pApple;
  6. pApple = GetInstance();
  7. SetColor(pApple, 1);
  8. printf("color = %d\n", GetColor(pApple));
  9. ReleaseInstance(pApple);
  10. //printf("color = %d\n", GetColor(pApple));// pApple released
  11. return 0;
  12. }

编译:

apple.cpp生成c++的静态库,再用apple_c.cpp生成一个wrapper的动态库libapple_c.so

再用main.c去调用这个动态库。

  1. # compile .cpp
  2. g++ -g -c apple.cpp -o apple.o
  3. g++ -g -c apple_c.cpp -o apple_c.o
  4. # build cpp static library
  5. ar rcs libapple.a apple.o
  6. # build c wraper libapple_c.so dynamic library
  7. g++ -g -fpic -shared -o libapple_c.so apple_c.o -L. -l apple -fvisibility=hidden
  8. # build main.c
  9. gcc -g main.c -o mainc -L. -l apple_c

结构体、类。已经在c++中定义过了,只需要定义对应的void *指针类型即可。

类的成员函数都要转换成普通的函数,一般将类对象指针作为第一个参数传入函数中。

enum类要在c头文件中重新定义

Exception处理。 c语言不支持Exception,所以异常需要在c++对应的wrapper cpp文件中进行处理。否则会在运行时出问题。

C语言封装的代码示例:

https://github.com/opentdf/client-cpp/blob/main/src/lib/include/tdf_client_c.h

https://github.com/opentdf/client-cpp/blob/main/src/lib/include/tdf_client.h

参考知识:

Standard C++ icon-default.png?t=N7T8https://isocpp.org/wiki/faq/mixing-c-and-cpp

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/43396
推荐阅读
相关标签
  

闽ICP备14008679号