You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swig与C#:无法为结构体数组成员赋值的问题求助

问题分析与解决方案

你的核心问题在于C#侧构造的内存布局和C++结构体中二维char数组的内存布局不匹配,导致SWIG生成的setter无法正确解析数据,以下是具体原因和修复方案:

原方法失败原因

第一种方法错误

C++中char routing_key[100][56]是连续的内存块(共100*56=5600字节),每个元素是56字节的ANSI字符串;而你用IntPtr[]构造的是指针数组(每个元素是一个字符串的内存地址),两者内存结构完全不同,SWIG生成的SWIGTYPE_p_a_56__char对应的是char(*)[56](指向56字节char数组的指针),而非char**(指针数组),因此无法匹配。

第二种方法错误

C#的char[,]是UTF-16编码的双字节字符数组,每个char占2字节;而C++的char是单字节ANSI字符,内存布局错位,直接pin传递会导致数据乱码,类型也不匹配。

正确解决方案

方案1:直接构造匹配C++内存布局的字节数组

模拟C++连续单字节内存块的结构,用byte[]存储数据后传递给SWIG:

// 分配与C++数组完全匹配的连续内存:100*56字节
byte[] routingKeyBuffer = new byte[100 * 56];

// 填充第一个字符串"abcd"为ANSI编码,复制到对应位置
byte[] firstStrBytes = Encoding.ASCII.GetBytes("abcd");
Array.Copy(firstStrBytes, 0, routingKeyBuffer, 0, firstStrBytes.Length);
// 剩余字节默认是0,正好对应C++的字符串终止符'\0'

// pin字节数组,获取首地址
GCHandle gch = GCHandle.Alloc(routingKeyBuffer, GCHandleType.Pinned);
IntPtr bufferPtr = gch.AddrOfPinnedObject();

// 构造SWIG类型并赋值
ReqSubscribeField_t subscribeField = new ReqSubscribeField_t();
subscribeField.routing_key = new SWIGTYPE_p_a_56__char(bufferPtr, true);

// 注意:若SWIG构造函数第二个参数为true,会接管内存管理,无需手动释放GCHandle;否则使用完需调用gch.Free()

方案2:修改SWIG接口,生成更易用的C#访问器

通过SWIG自定义typemap,让二维char数组直接映射为C#的string[],避免手动操作指针:

在你的SWIG接口文件(.i)中添加以下代码:

%module YourModuleName

// 为routing_key生成C#字符串数组的getter
%typemap(csgetter) char ReqSubscribeField::routing_key[100][56] {
    string[] result = new string[100];
    IntPtr basePtr = $imcall;
    for (int i = 0; i < 100; i++) {
        result[i] = Marshal.PtrToStringAnsi(basePtr + i * 56);
    }
    return result;
}

// 为routing_key生成C#字符串数组的setter
%typemap(cssetter) char ReqSubscribeField::routing_key[100][56] {
    IntPtr basePtr = $imcall;
    for (int i = 0; i < value.Length && i < 100; i++) {
        string str = value[i] ?? string.Empty;
        // 将字符串转为ANSI并填充到56字节,不足补'\0'
        byte[] bytes = Encoding.ASCII.GetBytes(str.PadRight(56, '\0'));
        Marshal.Copy(bytes, 0, basePtr + i * 56, 56);
    }
}

// 导入你的C++头文件
%include "your_header_file.h"

重新生成C#代码后,即可直接用字符串数组赋值:

ReqSubscribeField_t subscribeField = new ReqSubscribeField_t();
subscribeField.routing_key = new string[100];
subscribeField.routing_key[0] = "abcd";
// 其余元素默认空字符串,会自动填充'\0'

内容的提问来源于stack exchange,提问作者SongXiangGong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 03:36:30