加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 与nim返回的结构体数组包含一个字符串/ char *成员

发布时间:2020-12-15 06:20:17 所属栏目:百科 来源:网络整理
导读:来自c#的interoping nim dll可以调用并执行下面的代码 如果我将添加另一个调用GetPacks()的函数(proc),并尝试在每个元素的缓冲区上回显,我可以正确看到C#控制台中的输出 但是我无法传输数据,我尝试过一切,但我无法完成任务 proc GetPacksPtrNim(parSze: int,
来自c#的interoping nim dll可以调用并执行下面的代码

如果我将添加另一个调用GetPacks()的函数(proc),并尝试在每个元素的缓冲区上回显,我可以正确看到C#控制台中的输出
但是我无法传输数据,我尝试过一切,但我无法完成任务

proc GetPacksPtrNim(parSze: int,PackArrINOUT: var DataPackArr){.stdcall,exportc,dynlib.} =
  PackArrINOUT.newSeq(parSze)
  var dummyStr = "abcdefghij"
  for i,curDataPack in PackArrINOUT.mpairs:
    dummyStr[9] = char(i + int8'0')
    curDataPack = DataPack(buffer:dummyStr,intVal: uint32 i)

type
  DataPackArr = seq[DataPack]
  DataPack = object
    buffer: string
    intVal: uint32

当我在c / c中执行相同操作时,我使用的类型是IntPtr或char *
这很高兴包含返回的缓冲区成员

EXPORT_API void __cdecl c_returnDataPack(unsigned int size,dataPack** DpArr)
{
    unsigned int dumln,Index;dataPack* CurDp = {NULL};
    char dummy[STRMAX];
    *DpArr = (dataPack*)malloc( size * sizeof( dataPack ));
    CurDp = *DpArr;
    strncpy(dummy,"abcdefgHij",STRMAX);

    dumln = sizeof(dummy);

    for ( Index = 0; Index < size; Index++,CurDp++)
    {
        CurDp->IVal = Index;
        dummy[dumln-1] = '0' + Index % (126 - '0');
        CurDp->Sval = (char*) calloc (dumln,sizeof(dummy));
        strcpy(CurDp->Sval,dummy);
    }

}

c#签名上面的c代码

[DllImport(@"cdllI.dll",CallingConvention = CallingConvention.Cdecl),SuppressUnmanagedCodeSecurity]
    private static extern uint c_returnDataPack(uint x,DataPackg.TestC** tcdparr);

C#结构

public unsafe static class DataPackg
{

   [StructLayout(LayoutKind.Sequential)]
    public struct TestC
    {
        public uint Id;
        public IntPtr StrVal;
    }

}

最后调用这样的功能:

public static unsafe List<DataPackg.TestC> PopulateLstPackC(int ArrL)
    {
        DataPackg.TestC* PackUArrOut;
        List<DataPackg.TestC> RtLstPackU = new List<DataPackg.TestC>(ArrL);
        c_returnDataPack((uint)ArrL,&PackUArrOut);
        DataPackg.TestC* CurrentPack = PackUArrOut;
        for (int i = 0; i < ArrL; i++,CurrentPack++)
        {

            RtLstPackU.Add(new DataPackg.TestC() { StrVal = CurrentPack->StrVal,Id = CurrentPack->Id });
        }
        //Console.WriteLine("Res={0}",Marshal.PtrToStringAnsi((IntPtr)RtLstPackU[1].StrVal));//new string(RtLstPackU[0].StrVal));
        return RtLstPackU;
    }

如何从Nim生成类似的c代码?

它不一定是相同的代码,但效果相同,在c#我将能够读取字符串的内容.现在,int是可读的但字符串不是

编辑:

这是我试图让事情简单的事情
struct array of int members

更新:

似乎问题是我的Windows操作系统中的nim设置.
一旦我发现究竟是什么错误,我将会更新.

解决方法

Nim中的字符串类型不等同于C的const char *类型. Nim中的字符串表示为指针,指向堆分配的内存块,具有以下布局:
NI length;   # the length of the stored string
NI capacity; # how much room do we have for growth
NIM_CHAR data[capacity]; # the actual string,zero-terminated

请注意,这些类型是架构特定的,它们实际上是将来可以更改的编译器的实现细节. NI是架构默认的interger类型,NIM_CHAR通常相当于一个8位的char,因为Nim倾向于使用UTF8.

考虑到这一点,您有几个选择:

1)您可以教C#关于这个布局,并访问字符串缓冲区在正确的位置(上述注意事项适用).这种方法的一个示例实现可以在这里找到:
https://gist.github.com/zah/fe8f5956684abee6bec9

2)您可以在Nim代码中使用不同类型的缓冲区.可能的候选人是ptr char或固定大小的数组[char].第一个将要求您放弃自动垃圾收集,并保留一些用于手动内存管理的代码.第二个将放弃一点空间效率,它将对这些缓冲区的大小进行限制.

编辑:使用cstring也可能看起来很诱人,但它最终是危险的.当您将常规字符串分配给cstring时,结果将是一个正常的char *值,指向上述Nim字符串的数据缓冲区.由于Nim垃圾收集器正确地处理内部指针到分配的值,所以只要将cstring值放置在跟堆栈的跟踪位置,这将是安全的.但是当将它放在一个对象中时,cstring不会被跟踪,并且没有任何东西阻止GC释放内存,这可能会在你的C#代码中创建一个悬挂的指针.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读