SWIG:如何将C 对象的数组从C#传递到C
SWIG: How do i pass an array of C++ objects from C# to C++?
我有一个C 数据类,该类别存储了一个指向分配的内存的指针;我使用Swig生成的包装器从C#进行实例化和消费毫无疑问。当我尝试在包装库中调用一个函数时,我的问题就会出现,该函数想要这些数据类数量。我每次都碰到细分故障。我尝试了下面列出的两种方法。
简而言之,我的情况是
class DataClass
{
char* _data;
...
}
void printDataClassArray(DataClass *toPrint, std::size_t size)
{ ... }
默认情况下,函数printDataClassArray
被包裹为void printDataClassArray(DataClass toPrint, int size)
,我尝试了两种不同的方法来克服这一点。我在下面发布完整的代码,以帮助将尝试帮助我的好灵魂:example.h
包含我要包装的C 库,example.i
包含SWIG接口代码,consumer.cs
是一个C#功能,用于消耗导出的功能和类。p>我尝试研究了这一点,特别是我遵循了此线程:错误的值以参数为c库,但我没有找到答案。我不知道我是否缺少明显的东西,但是我认为这应该是SWIG中的例子的一部分,因为这是一个相当普遍的情况。
我尝试了两种方法,即使用CSHARP_ARRAYS
并使用array_class
,但它们都没有使用。请参阅下面的SWIG代码,并进一步向下列出。
使用 _csharp_arrays _
CSHARP_ARRAYS(DataClass, DataClass);
%apply DataClass INPUT[]{ DataClass *toprint }
%inline %{
static void PrintAllDataArray(DataClass *toprint, std::size_t size)
{
PrintAllData(toprint, size);
}
%}
使用 _array_class _
// Methodology 2
%array_class(DataClass, DataClassArray);
%inline %{
static void PrintAllVariants(DataClassArray va, std::size_t size)
{
PrintAllData(DataClassArray_cast(&va), size);
}
%}
示例.h
#include <cstring> // for memcpy
#include <string> // for std::string
#include <sstream>
#include <iostream>
#include "assert.h"
inline char* copyString(const char* value, std::size_t size) {
char* newstring = new char[size + 1];
memcpy(newstring, value, size);
newstring[size] = 0;
std::cout << "Allocated string of " << size << " characters at " << reinterpret_cast<const void*>(newstring) << std::endl;
return newstring;
}
struct DataEncapsulator {
struct StringValue {
const char* ptr;
int size;
} svalue;
};
inline DataEncapsulator copyData(DataEncapsulator source) {
DataEncapsulator copy = source;
copy.svalue.ptr = copyString(source.svalue.ptr,
source.svalue.size);
return copy;
}
inline void deleteString(const char* string)
{
std::printf("Deallocating string at %pn", reinterpret_cast<const void*>(string));
delete[] string;
}
class DataClass {
DataEncapsulator impl_;
public:
DataClass()
{
impl_.svalue.ptr = NULL;
std::cout << "Empty constructor called on " << myAddress() << std::endl;
}
DataClass(const char* string)
{
std::cout << "Constructor called on " << myAddress() << std::endl;
std::size_t len = std::strlen(string);
impl_.svalue.ptr = copyString(string, len);
impl_.svalue.size = len;
}
DataClass(const DataClass& other) {
std::cout << "Copy constructor, copying from " << other.myAddress() << " to " << myAddress() << std::endl;
impl_ = copyData(other.impl_);
}
~DataClass()
{
std::cout << "Destructor called on " << myAddress() << std::endl;
deleteString(impl_.svalue.ptr);
}
std::string myAddress()const
{
std::ostringstream strs;
strs << reinterpret_cast<const void*>(this);
return strs.str();
}
std::string toString() const
{
std::ostringstream strs;
strs << """ << impl_.svalue.ptr << "" - string address: " << reinterpret_cast<const void*>(impl_.svalue.ptr);
return strs.str();
}
const char* c_str() const
{
return impl_.svalue.ptr;
}
DataClass& operator=(const DataClass& other) {
std::cout << "Assignment, copying from " << other.myAddress() << " to " << myAddress() << std::endl;
deleteString(impl_.svalue.ptr);
impl_ = copyData(other.impl_);
return *this;
}
};
static void PrintAllData(DataClass toprint[], std::size_t size)
{
std::cout << "PrintAllVariants passed array of " << size << " variants at " << reinterpret_cast<const void*>(toprint) << std::endl;
if (size > 0)
{
for (std::size_t i = 0; i < size; i++)
std::cout << i << ": " << toprint[i].myAddress() << " - " << toprint[i].toString() << std::endl;
}
}
示例.i
%module example
%include "std_string.i"
%include "arrays_csharp.i"
%include "carrays.i"
#ifdef _WIN32
%include <windows.i>
#endif
%inline %{
namespace std {
typedef unsigned int size_t;
}
%}
%ignore DataEncapsulator;
%ignore copyString;
%ignore copyData;
%ignore deleteString;
%{
#include "example.h"
%}
%rename(copy) *::operator=;
%include "example.h"
// Methodology 1
CSHARP_ARRAYS(DataClass, DataClass);
%apply DataClass INPUT[]{ DataClass *toprint }
%inline %{
static void PrintAllDataArray(DataClass *toprint, std::size_t size)
{
PrintAllData(toprint, size);
}
%}
// Methodology 2
%array_class(DataClass, DataClassArray);
%inline %{
static void PrintAllVariants(DataClassArray va, std::size_t size)
{
PrintAllData(DataClassArray_cast(&va), size);
}
%}
consumer.cs
var a = new DataClass("first");
var b = new DataClass("second");
// Methodology 1
DataClassArray va = new DataClassArray(2);
va.setitem(0, a);
va.setitem(1, b);
example.PrintAllVariants(va, 2);
// Methodology 2
DataClass[] da = new DataClass[2];
da[0] = a;
da[1] = b;
example.PrintAllDataArray(da, 2);
Console.WriteLine();
经过大量的调查,要避免使用std::vector
,这是朋友建议的一种非常简单的解决方案:在方法论2中更改助手功能的签名2以通过DataClassArray
通过参考,因此来自:
static void PrintAllVariants(DataClassArray va, std::size_t size)
to
static void PrintAllVariants(DataClassArray &va, std::size_t size)
希望它有帮助。
相关文章:
- 销毁C++中动态分配的内存(数组对象)
- 数组对象的生存期是否在重用其元素存储时结束?
- 为什么顶点数组对象会导致错误?
- 具有纯虚函数和指针数组对象类型的父类的指针数组
- 这是使用构造函数初始化数组对象的最佳方法吗?
- OpenGL 顶点数组对象与 tinyobjloader
- 将数组/对象/结构列表从C#库中传递给C MFC应用程序
- C++ RapidJson 帮助反序列化数组对象
- ptrdiff_t可以表示指向同一数组对象元素的指针的所有减法吗?
- 检查成员函数是否返回临时对象或数组对象
- 为什么 std::variant 不能容纳数组对象类型,而联合可以?
- 当数组对象以函数参数传递时,为什么复制构造函数会自称
- 如何使用箭头指针打印出一类数组对象,这些对象中有多个分数
- C++17 std::shared_ptr<> 类数组对象的重载运算符 []
- 添加两个具有运算符重载的数组对象,从而导致分段错误
- opengl:两个不同的矢量可以绑定到同一个顶点数组对象吗
- 使用相同的数据填充数组对象或使用指针
- 方法用于最快的分配,并且不需要将动态大小的数组对象作为局部变量
- 如何将2d数组对象传递给c++中的函数
- ReferenceTable溢出(jni-android),数组对象释放