首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >将C++命名空间枚举封装到C接口

将C++命名空间枚举封装到C接口
EN

Stack Overflow用户
提问于 2013-12-26 14:32:05
回答 2查看 2.4K关注 0票数 1

我正在尝试将现有的第三方 C++库封装到C接口,以便它可以用于另一种语言的绑定。我很难弄清楚如何包装一个名称空间枚举,而不是仅仅重新定义它:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Existing C++ 3rd party library header
namespace foo {
    enum Fruit {
        APPLE = 0,
        ORANGE
    }
}

所以我用一个extern "C"块包装了我的.{h,cpp},我只是不知道如何将foo::Fruit枚举导出到C接口中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// wrapped.h
#ifdef __cplusplus
extern "C" {
#endif

// I don't want to do this
typedef enum Fruit {
    APPLE = 0,
    ORANGE
} Fruit;

#ifdef __cplusplus
}
#endif
#endif

是否可以将(镜像) foo::Fruit从C++库导出到我的C包装器中作为Fruit

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-12-26 15:17:49

编辑:我只是注意到您想包装一个现有的库而不修改它。

恐怕你那时候运气不好。通常,在没有C编译器阻塞的情况下,从C++代码中提取枚举成员是不可能的。

在实践中,您可以选择是以编程方式将自己的枚举集转换为接口中的C++版本,尝试准确地镜像C++,并放置一堆静态断言进行二次检查,或者在理论上甚至通过脚本过滤掉它们。

恐怕这里没有很好的选择。为了记录在案,我倾向于选择这些糟糕的第一个选项。

就我个人而言,我可能会很懒,只会坚持使用C版本。

尽管如此,如果需要并且常量的数量很大,您可以做一些宏魔术,以便根据需要使用C风格的“名称空间”获得单个定义。

首先,通过宏定义所有枚举条目的单个标头:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* Fruit.h */
FOO_ENUM(APPLE) = 0,
FOO_ENUM(ORANGE)

然后在C头中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* C interface */
typedef enum {
#   define FOO_ENUM(id) FOO_##id
#   include "Fruit.h"
#   undef FOO_ENUM
} Foo_Fruit_t;

最后,在C++头中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// C++ interface
namespace Foo {
    enum Fruit_t {
#       define FOO_ENUM(id) id
#       include "Fruit.h"
#       undef FOO_ENUM
    };
}

当然,还有很多其他的选择。例如,如果您不介意污染C++中的全局命名空间,那么始终可以在C接口中直接定义完整的枚举,并在定义的C++版本中复制单个枚举成员。

票数 3
EN

Stack Overflow用户

发布于 2016-08-17 09:56:05

最近,我在一个enums库的C包装器中遇到了这个特殊的问题,它引起了很大的麻烦。

我的解决方案显示在下面的基本工作示例中,但它在一些地方非常不雅观。它本质上是一种翻译方法。

人们必须警惕,不要在enums上两度声明任何事情。该示例传递intstringchar数组和enum

用C++编写的库头。这是将要包装的库。MyClass.h:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#ifndef __MYCLASS_H
#define __MYCLASS_H

#include <iostream>

namespace MyNamespace {

using namespace std;

enum EnumControlInterface {HIDController=1, UVCController=2};

class MyClass {

private:
         int m_i;

         string m_text;

         EnumControlInterface _controller;

public:
         MyClass(int val);

         ~MyClass();

         void int_set(int i);

         void string_set(string text);

         int int_get();

         string string_get();

         void writeEnum(EnumControlInterface MyInterface);

         EnumControlInterface readEnum();
    };
};
#endif

C++实现MyClass.cpp:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "MyClass.h"

namespace MyNamespace {

    MyClass::MyClass(int val) {
        cout << "MyClass is being created" << endl;
        cout << "The parameter passed to the MyClass constructor is: " << val << endl;
    }

    MyClass::~MyClass() {
        cout << "MyClass is being destroyed" << endl;

    }

    void MyClass::writeEnum(EnumControlInterface MyInterface) {
        _controller = MyInterface;
        cout << "The interface control Enum is set in MyClass.cpp as: " << _controller << endl;
    }

    EnumControlInterface MyClass::readEnum() {
        return _controller;
    }

    void MyClass::string_set(std::string text) {
        m_text = text;
    }

    string MyClass::string_get() {
        return m_text;
    }

    void MyClass::int_set(int i) {
        m_i = i;
    }

    int MyClass::int_get() {
        return m_i;
    }

}

一个"C包装器“头文件MyWrapper.h,它包装MyClass.h:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#ifndef __MYWRAPPER_H
#define __MYWRAPPER_H

#ifdef __cplusplus
namespace MyNamespace {
    extern "C" {
#endif

        typedef enum WrapperEnumControlInterface {WrapHIDController=1, WrapUVCController=2} WrapperEnumControlInterface;

        typedef struct MyClass MyClass;

        MyClass* newMyClass(int val);

        void MyClass_int_set(MyClass* v, int i);

        int MyClass_int_get(MyClass* v);

        void MyClass_string_set(MyClass* v, char* text);

        char* MyClass_string_get(MyClass* v);

        void MyClass_writeEnum(MyClass* v, WrapperEnumControlInterface MyInterface);

        WrapperEnumControlInterface MyClass_readEnum(MyClass* v);

        void deleteMyClass(MyClass* v);

#ifdef __cplusplus
    }
}
#endif
#endif

"C包装器“实现是用C和C++混合编写的。具体来说,函数定义必须是C,传递和返回的参数也必须是C类型。在函数内部和预处理器区域内,__cplusplus、C或C++都应该很好。

例如,不能要求extern "C"块中的函数接受std::string类型。它将破坏包装器的目标:只公开操作底层C++库的C代码。extern "C"确定没有名称损坏的公开内容(请参阅questions about name mangling in C++)。__cplusplus由(许多) C++编译器定义。

MyWrapper.cc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "MyClass.h"
#include "MyWrapper.h"
#include <vector>

namespace MyNamespace {
extern "C" {

    MyClass* newMyClass(int val) {
            return new MyClass(val);
    }

    void deleteMyClass(MyClass* v) {
            delete v;
    }

    void MyClass_int_set(MyClass* v, int i) {
        v->int_set(i);
    }

    int MyClass_int_get(MyClass* v) {
        return v->int_get();
    }

    void MyClass_string_set(MyClass* v, char* text) {
        //convert incomming C char* to a C++ string
        string stringToSend = string(text);

        cout << "the string received from the program by the wrapper is " << text << endl;
        cout << "the string sent to the library by the wrapper is " << stringToSend << endl;

        v->string_set(stringToSend);
    }

    char* MyClass_string_get(MyClass* v) {

        string result = v->string_get();

        cout << "the string received from the library by the wrapper is " << result << endl;

        // Convert the C++ string result to a C char pointer and return it. Use vectors to do the memory management.
        // A vector type of as many chars as necessary to hold the result string
        static vector<char> resultVector(result.begin(), result.end());

        cout << "the data in the vector who's pointer is returned to the program by the wrapper is: " << &resultVector[0] << endl;

        return (&resultVector[0]);
    }

    void MyClass_writeEnum(MyClass* v, WrapperEnumControlInterface MyInterface) {
        v->writeEnum((EnumControlInterface)MyInterface);
    }

    WrapperEnumControlInterface MyClass_readEnum(MyClass* v) {
        EnumControlInterface result = v->readEnum();
        return (WrapperEnumControlInterface)result;
    }

}
}

通过包装器Cproject.c调用C++库的C程序:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "MyWrapper.h"
#include "stdio.h"

int main(int argc, char* argv[]) {

    struct MyClass* clsptr = newMyClass(5);

    MyClass_int_set(clsptr, 3);

    printf("The int read back in Cproject.c is: %i\n", MyClass_int_get(clsptr));

    MyClass_writeEnum(clsptr, WrapUVCController);

    printf("The enum read back in Cproject.c is: %d\n", MyClass_readEnum(clsptr));

    MyClass_string_set(clsptr, "Hello");

    char *textReadBack = MyClass_string_get(clsptr);

    printf("The text read back in Cproject.c is: %s \n", textReadBack);

    deleteMyClass(clsptr);

    return 0;
}

为了完整起见,一个直接调用C++库而不使用包装器CPPProgram.cpp的C++项目就这么短了!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "MyClass.h"
#include <iostream>

using namespace std;
using namespace MyNamespace;

int main(int argc, char* argv[]) {

    MyClass *c = new MyClass(42);

    c->int_set(3);

    cout << c->int_get() << endl;

    c->writeEnum(HIDController);

    cout << c->readEnum() << endl;

    c->string_set("Hello");

    cout << c->string_get() << endl;

    delete c;
}

MyClass C++类被编译到静态库中,包装器被编译到共享库中--没有特殊的原因,两者都可以是静态的或共享的。

调用包装库(Cproject.c)的C程序必须与C++编译器(G++等)链接。

显然,这个例子没有一个真正的应用程序。它在结构上基于c/,但添加了enum位。

编写包装器的人通常无法访问他们试图包装的库的源代码(在本例中是MyClass.cpp),他们将分别拥有.so或.dll、.a或.lib (用于Linux和.lib)、共享库和静态库。没有必要为C++库提供源代码。只有C++库的头文件才能编写有效的包装器。

我把这个问题写出来,部分是为了为原来的问题提供一个较详尽的答案,这个答案可以很容易地抄写出来,而且可以随意使用,但也因为这是我迄今唯一能够解决问题的方法,而且我认为这是不令人满意的。我希望能够用包装公共成员函数的方式包装enums,而不是用稍微不同的名称在包装器中重新创建enums

经证明有用的相关信息来源:

c/

How to cast / assign one enum value to another enum

Developing C wrapper API for Object-Oriented C++ code

Converting a C-style string to a C++ std::string

Returning pointer from a function

*

当然,所有不安全、错误等编码实践都是我的错。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20792121

复制
相关文章
图像翻转
算法:图像翻转是用于对图像进行镜像翻转处理。水平翻转用于对图像进行水平方向上镜像处理;垂直翻转用于对图像进行垂直方向上镜像处理。对角翻转用于对水平方向上和垂直方向上镜像处理。图像翻转不是图像反转。图像翻转可以通过图像旋转获得。图像翻转应用在图像增强、网页设计等领域。
裴来凡
2022/05/28
1.3K0
图像翻转
opencv图像翻转、图像旋转
淼学派对
2023/10/14
3330
opencv图像翻转、图像旋转
LeetCode - 翻转图像
原题地址:https://leetcode-cn.com/problems/flipping-an-image/
晓痴
2019/08/06
5500
LeetCode - 翻转图像
SilverLight实现绕垂直中线翻转效果
主要通过StoryBoard来控制PlaneProjection的RotationY来实现
MJ.Zhou
2022/05/07
4430
Silverlight制作逐帧动画
打算用sl来制作一个游戏,我曾经有flash开发游戏的经验.现在想用sl来做.打算记录下我开发游戏探索的过程. 打开http://www.emu-zone.org/www3/host/emugif/
用户1172164
2018/01/16
1K0
Silverlight制作逐帧动画
Silverlight初级教程-动画
Silverlight初级教程 动画 在这一节里将要用到在“认识工作区”中提到的时间抽了。这里将和学习flash的过程一样做一个最简单的动画。 silverlight中的动画是以“storyboard”的形式表现出来。“storyboard”你可以认为是flash中的时间轴。  flash中只有一个时间轴,而在silverlight中却可以有多个“storyboard”。 在flash中是有一个帧频的概念的,例每秒12帧、每秒30帧等。而在silverlight中则是完全的基于时间的,例
用户1172164
2018/01/16
6190
用silverlight做动画-相机
用silverlight做动画-相机 适合初学者学习 做一个相机的动画 和做flash动画一样,准备好素材 将素材放入项目中 开始正式制作前为了方便以后重用,就把这个动画做成usercontrol(和flash中的‘MovieClip’概念是一样的) 创建一个UserControl 图片放入舞台中并且调整好位置 用钢笔在最上层画一个图像做遮罩使用,和flash中的概念一样。 讲上边的小图放入一个Canvas容器中 选中Canvas容器和刚刚画出的图形制作遮罩 将刚刚遮罩过的Canvas容器
用户1172164
2018/03/01
8610
CSS骰子翻转动画
---- <!doctype html> <html> <head> <meta charset="utf-8"> <title>CSS3骰子翻转动画</title> <style> body { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; col
我不是费圆
2020/12/17
5940
OpenCV之图像翻转
python代码: import cv2 as cv import numpy as np src = cv.imread("./test.png") cv.namedWindow("input", cv.WINDOW_AUTOSIZE) cv.imshow("input", src) # X Flip 倒影 dst1 = cv.flip(src, 0); cv.imshow("x-flip", dst1); # Y Flip 镜像 dst2 = cv.flip(src, 1); cv.imshow(
MachineLP
2021/07/19
3040
OpenCV之图像翻转
[Python图像处理] 六.图像缩放、图像旋转、图像翻转与图像平移
该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类、目标检测应用。
Eastmount
2021/12/02
5.8K0
[Python图像处理] 六.图像缩放、图像旋转、图像翻转与图像平移
LeetCode 832. 翻转图像
水平翻转图片就是将图片的每一行都进行翻转,即逆序。例如,水平翻转 [1, 1, 0] 的结果是 [0, 1, 1]。
freesan44
2020/06/03
2300
OpenCV图像处理(八)---图像缩放VS图像翻转
牛顿第三运动定律的常见表述是:相互作用的两个物体之间的作用力和反作用力总是大小相等,方向相反,作用在同一条直线上。该定律是由艾萨克·牛顿在1687年于《自然哲学的数学原理》一书中提出的。牛顿第三运动定律和第一、第二定律共同组成了牛顿运动定律,阐述了经典力学中基本的运动规律。
用户5410712
2022/06/01
7620
OpenCV图像处理(八)---图像缩放VS图像翻转
[UWP]使用CompositionAPI的翻转动画
在 使用GetAlphaMask和ContainerVisual制作长阴影(Long Shadow) 这篇文章里我介绍了一个包含长阴影的番茄钟,这个番茄钟在状态切换时用到了翻转动画,效果如上所示,还用到了弹簧动画,可以看到翻转后有点回弹。本来打算自己这个动画效果写的,但火火已经写好了这个FlipSide控件,Github地址在这里,这篇文章就介绍下这个控件的部分原理。
dino.c
2019/11/14
7610
LeetCode 0832. 翻转图像
水平翻转图片就是将图片的每一行都进行翻转,即逆序。例如,水平翻转 1, 1, 0 的结果是 0, 1, 1。
Yano_nankai
2021/02/23
2040
LeetCode 0832. 翻转图像
cv图像翻转,EmguCV图像旋转「建议收藏」
i use this codeprivate void button12_Click(object sender, EventArgs e)
全栈程序员站长
2022/07/25
7270
Qt官方示例-Qml翻转动画
❝示例演示翻转动画(沿着x轴或y轴翻转动画)。❞ 主要代码: import QtQuick 2.0 Flipable { id: container property alias source: frontImage.source property bool flipped: true property int xAxis: 0 property int yAxis: 0 property int angle: 0 width: front.
Qt君
2023/03/17
7630
Qt官方示例-Qml翻转动画
Python图像增强(翻转和旋转)
在训练神经网络的时候,经常需要对原始图像做各种各样的增强来增加数据量,最常见的也就是旋转和翻转操作了,实现这两种操作也多种多样,本博客就是来探究不同操作带来的结果
用户7886150
2021/01/05
2.4K0
TensorFlow 图像预处理(二) 图像翻转,图像色彩调整
本文介绍了TensorFlow中的图像预处理方法,包括图像翻转、图像色彩调整、图像归一化等操作。通过这些操作,可以有效地提高图像的质量和可用性。同时,文章还介绍了如何使用TensorFlow进行图像增强和预处理,以便在训练模型时获得更好的性能。
chaibubble
2018/01/02
1.9K0
TensorFlow 图像预处理(二) 图像翻转,图像色彩调整
09:图像旋转翻转变换
09:图像旋转翻转变换 总时间限制: 1000ms 内存限制: 65536kB描述 给定m行n列的图像各像素点灰度值,对其依次进行一系列操作后,求最终图像。 其中,可能的操作及对应字符有如下四种: A:顺时针旋转90度; B:逆时针旋转90度; C:左右翻转; D:上下翻转。 输入第一行包含两个正整数m和n,表示图像的行数和列数,中间用单个空格隔开。1 <= m <= 100, 1 <= n <= 100。 接下来m行,每行n个整数,表示图像中每个像素点的灰度值,相邻两个数之间用单个空格隔开。灰度值
attack
2018/04/03
1.8K0
Leetcode#832. Flipping an Image(翻转图像)
水平翻转图片就是将图片的每一行都进行翻转,即逆序。例如,水平翻转 [1, 1, 0] 的结果是 [0, 1, 1]。
武培轩
2018/09/28
3780

相似问题

翻转动画后Silverlight屏幕模糊

10

Android翻转图像动画

20

CSS动画:如何翻转图像?

226

jQuery动画图像翻转

33

在动画过程中翻转图像

123
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文