C#传结构体给C++,类型转换,封送结构体,动态申请数组空间

时间:2022-08-30 19:56:18
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct SASK //股票报价返回
    {
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 603)]
        public Ask[] m_ask; //股票报价
    }

C#中,请问怎么将SizeConst 设置成动态变化的,就是封送给C++ dll是,这个结构体的m_ask这次可能是603,下次可能是600,下次可能是500. 
SizeConst 好像是接收特性形参类型的常量表达式、typeof 表达式或数组创建表达式

有没有办法,望高手指导。
再不行换其他思路。

25 个解决方案

#1


除非在运行时动态编译代码,否则attrbute是不能更改的。

#2


用数组和指针就行了,那个成员定义成指针,指向一个动态分配的数组

#3


动态编译代码好像很烦啊,有没有其他思路能解决这个问题,我就是封送这个结构体给dll,但结构体里面的数组元素个数是不确定的。

#4


你直接传数组不就可以了,为什么要用结构体?

#5


2楼的用数组和指针,在C#怎么用,关键这个数组还要加上面那个属性啊,具体语法能不能给我举个例子

#6


这个结构体完整的应该是这样的
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct SASK  //股票报价返回
    {
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 603)]
        public Ask[] m_ask; //股票报价
        public int m_a;
        public byte m_b;
    }
然后转成C#的IntPtr类型 对应那边是void *info   C# void test(IntPtr info)  C++ void test(void * info)

#7


引用 5 楼 gxp402175383 的回复:
2楼的用数组和指针,在C#怎么用,关键这个数组还要加上面那个属性啊,具体语法能不能给我举个例子


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct SASK  //股票报价返回
        {
            
            public Ask* m_ask; //股票报价
            public int m_a;
            public byte m_b;
        }

        static void TestAsk()
        {
            SASK sa;
            var askList = new List<Ask>();
            //askList.add(xxxx);
            var asks=askList.ToArray();
            fixed (Ask* pask = asks)
            {
                sa.m_ask = pask;
                //调用函数......
            }
            
        }

#8


soaringbird  高手,如果这个方法可行,请问结构体里面public Ask* m_ask;  这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了

#9


引用 8 楼 gxp402175383 的回复:
soaringbird  高手,如果这个方法可行,请问结构体里面public Ask* m_ask;  这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了

你先把C++原型贴出来,确定一下怎么改写.
unsafe加在类、结构、方法的声明前面。在项目属性里还有一个开关,选上。

#10


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct SASK //股票报价返回
    {
     public intptr
    }

#11


引用 9 楼 soaringbird 的回复:
Quote: 引用 8 楼 gxp402175383 的回复:

soaringbird  高手,如果这个方法可行,请问结构体里面public Ask* m_ask;  这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了

你先把C++原型贴出来,确定一下怎么改写.
unsafe加在类、结构、方法的声明前面。在项目属性里还有一个开关,选上。


C++发送给服务器结构体: struct base
{
unsigned char a;
short b;
};

        struct AA: public base
{
unsigned short c;
BB d[603];
};

        struct BB
{
unsigned short e;
CC f;
};

        struct CC
{
unsigned char g;
char h[10];
};
调用的接口函数 sendmsg(void *msg)


C++从服务器接收的结构体:
     struct base
{
unsigned char a;
short b;
};

        struct DD: public base
{
unsigned short o;
EE p[603];
};

        struct EE
{
unsigned short q;
FF r;
};

        struct FF
{
unsigned char s;
char t[10];
};
接收的话给的是内存地址,通过Marshal.PtrToStructure来转,问题关键是接收和发送的两大结构体里面有个类型数组,譬如现在我写的 603这个大小,翻译成C#应该就是我在1楼写的SizeConst = 603。
问题就是 这个603是动态的,可能下次发送的大小是500或400。在C++里面,可以把它设置成1,然后动态申请n*sizeof(BB)的空间,请问C#要怎么使它成动态的

#12


引用 11 楼 gxp402175383 的回复:
Quote: 引用 9 楼 soaringbird 的回复:

Quote: 引用 8 楼 gxp402175383 的回复:

soaringbird  高手,如果这个方法可行,请问结构体里面public Ask* m_ask;  这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了

你先把C++原型贴出来,确定一下怎么改写.
unsafe加在类、结构、方法的声明前面。在项目属性里还有一个开关,选上。


C++发送给服务器结构体: struct base
{
unsigned char a;
short b;
};

        struct AA: public base
{
unsigned short c;
BB d[603];
};

        struct BB
{
unsigned short e;
CC f;
};

        struct CC
{
unsigned char g;
char h[10];
};
调用的接口函数 sendmsg(void *msg)


C++从服务器接收的结构体:
     struct base
{
unsigned char a;
short b;
};

        struct DD: public base
{
unsigned short o;
EE p[603];
};

        struct EE
{
unsigned short q;
FF r;
};

        struct FF
{
unsigned char s;
char t[10];
};
接收的话给的是内存地址,通过Marshal.PtrToStructure来转,问题关键是接收和发送的两大结构体里面有个类型数组,譬如现在我写的 603这个大小,翻译成C#应该就是我在1楼写的SizeConst = 603。
问题就是 这个603是动态的,可能下次发送的大小是500或400。在C++里面,可以把它设置成1,然后动态申请n*sizeof(BB)的空间,请问C#要怎么使它成动态的

先去了解一下在struct 里面数组如何存储的

#13


使用用数组和指针,把那个成员定义成指针,指向一个动态分配的数组应该就可以了

#14


引用 13 楼 u010483061 的回复:
使用用数组和指针,把那个成员定义成指针,指向一个动态分配的数组应该就可以了



能不能举一个例子啊,语法写上后有报错。

#15


BB  d[603];
这个在c++里是BB d[1]还是 BB*d  ?

#16


引用 15 楼 soaringbird 的回复:
BB  d[603];
这个在c++里是BB d[1]还是 BB*d  ?


在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

#17


引用 16 楼 gxp402175383 的回复:
Quote: 引用 15 楼 soaringbird 的回复:

BB  d[603];
这个在c++里是BB d[1]还是 BB*d  ?


在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

我怎么没见过这种用法,通常是用指针动态分配空间的

#18


该回复于2013-09-03 08:31:17被管理员删除

#19


引用 16 楼 gxp402175383 的回复:
Quote: 引用 15 楼 soaringbird 的回复:

BB  d[603];
这个在c++里是BB d[1]还是 BB*d  ?


在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

用intptr
传递的时候用Marshal.UnsafeAddrOfPinnedArrayElement 
如果你能确定尺寸,也可以用Marshal.AllocHGlobal

#20



在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教
我怎么没见过这种用法,通常是用指针动态分配空间的

它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做

#21


引用 19 楼 hdt 的回复:
Quote: 引用 16 楼 gxp402175383 的回复:

Quote: 引用 15 楼 soaringbird 的回复:

BB  d[603];
这个在c++里是BB d[1]还是 BB*d  ?


在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

用intptr
传递的时候用Marshal.UnsafeAddrOfPinnedArrayElement 
如果你能确定尺寸,也可以用Marshal.AllocHGlobal


你的意思是写成这样?
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct SASK
        {
            
            public intptr m_ask;
            public int m_a;
            public byte m_b;
        }

        static void TestAsk()
        {
            SASK sa;
            var askList = new List<Ask>();
            //askList.add(xxxx);
            var asks=askList.ToArray();
            fixed (Ask* pask = asks)
            {
                sa.m_ask = pask;
                //调用函数......
            }
            
        }

#22


引用 20 楼 gxp402175383 的回复:
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

我怎么没见过这种用法,通常是用指针动态分配空间的

它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做

难道是 BB d[1]; d=malloc(603*sizeof(BB)); 这样编译都过不了啊

#23


引用 22 楼 soaringbird 的回复:
Quote: 引用 20 楼 gxp402175383 的回复:


在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

我怎么没见过这种用法,通常是用指针动态分配空间的


它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做

难道是 BB d[1]; d=malloc(603*sizeof(BB)); 这样编译都过不了啊

可以的,本来想贴出来,上次有个人qq发我的,一时找不到了,最终肯定是动态申请,malloc刚才我也有问题,是怎么个语法c++里有点不清楚了。

#24



struct AA
{
   int size;
   BB d[1];
};


在C++里面,之所有有BB d[1]这种写法,它表示至少有一个BB, 跟在一个size后面。因此在内存布局上,他们必须是 连续的。

struct Point
{
    int X, Y;
};

struct PointList
{
    int Length;
    Point Points[1];  //<--
};

extern "C" _declspec(dllexport) Point Sum(PointList& pointList)
{
    Point result = {};
    for(int i = 0; i < pointList.Length; i++)
    {
        result.X += pointList.Points[i].X;
        result.Y += pointList.Points[i].Y;
    }
    return result;
}

void Test()
{
    PointList* ptr = (PointList*)malloc(4 + sizeof(Point) * 3);
    ptr->Length = 3;

    ptr->Points[0].X = 1;
    ptr->Points[0].Y = 2;
    ptr->Points[1].X = 11;
    ptr->Points[1].Y = 22;
    ptr->Points[2].X = 111;
    ptr->Points[3].Y = 222;
    // ptr指向的内存为:  [3,1,2,11,22,111,222]

    Point sum = Sum(*ptr);  // sum.X=123, sum.Y=246
    free(ptr);
}


对C#来说,带有的关键就是内存布局的兼容,你可以用IntPtr,也可以用byte[],但是,要提供一段连续的内存[3,1,2,11,22,111,222]。例子可以这样写:

private void button1_Click(object sender, EventArgs e)
{
    Point[] points = new Point[]
    {
        new Point(1,2),
        new Point(11,22),
        new Point(111,222),
    };

    int int32InBytes = Marshal.SizeOf(typeof(int));
    int arrayInBytes = Marshal.SizeOf(typeof(Point)) * points.Length;

    // 写PointList.Length
    byte[] buffer = new byte[int32InBytes + arrayInBytes];
    BitConverter.GetBytes(points.Length).CopyTo(buffer, 0);

    // 写PointList.Points
    GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);
    Marshal.Copy(gc.AddrOfPinnedObject(), buffer, 4, buffer.Length - 4);
    gc.Free();

    Point sum = Sum(buffer);  // X=123, Y=246
}

[DllImport("xxx", CallingConvention = CallingConvention.Cdecl)]
extern static Point Sum(byte[] buffer);


#25


引用 24 楼 gomoku 的回复:

struct AA
{
   int size;
   BB d[1];
};


在C++里面,之所有有BB d[1]这种写法,它表示至少有一个BB, 跟在一个size后面。因此在内存布局上,他们必须是 连续的。

struct Point
{
    int X, Y;
};

struct PointList
{
    int Length;
    Point Points[1];  //<--
};

extern "C" _declspec(dllexport) Point Sum(PointList& pointList)
{
    Point result = {};
    for(int i = 0; i < pointList.Length; i++)
    {
        result.X += pointList.Points[i].X;
        result.Y += pointList.Points[i].Y;
    }
    return result;
}

void Test()
{
    PointList* ptr = (PointList*)malloc(4 + sizeof(Point) * 3);
    ptr->Length = 3;

    ptr->Points[0].X = 1;
    ptr->Points[0].Y = 2;
    ptr->Points[1].X = 11;
    ptr->Points[1].Y = 22;
    ptr->Points[2].X = 111;
    ptr->Points[3].Y = 222;
    // ptr指向的内存为:  [3,1,2,11,22,111,222]

    Point sum = Sum(*ptr);  // sum.X=123, sum.Y=246
    free(ptr);
}


对C#来说,带有的关键就是内存布局的兼容,你可以用IntPtr,也可以用byte[],但是,要提供一段连续的内存[3,1,2,11,22,111,222]。例子可以这样写:

private void button1_Click(object sender, EventArgs e)
{
    Point[] points = new Point[]
    {
        new Point(1,2),
        new Point(11,22),
        new Point(111,222),
    };

    int int32InBytes = Marshal.SizeOf(typeof(int));
    int arrayInBytes = Marshal.SizeOf(typeof(Point)) * points.Length;

    // 写PointList.Length
    byte[] buffer = new byte[int32InBytes + arrayInBytes];
    BitConverter.GetBytes(points.Length).CopyTo(buffer, 0);

    // 写PointList.Points
    GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);
    Marshal.Copy(gc.AddrOfPinnedObject(), buffer, 4, buffer.Length - 4);
    gc.Free();

    Point sum = Sum(buffer);  // X=123, Y=246
}

[DllImport("xxx", CallingConvention = CallingConvention.Cdecl)]
extern static Point Sum(byte[] buffer);



请问:
报了Object contains non-primitive or non-blittable data错误,在GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);这句话。
我的结构体在Point还有个自定义类型参数,是不是这个引起的, 没查出来,然后这个头还要不要写  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct Point
{
    int X, Y;
     TT _t;
};
public struct TT
{
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string str;
}

#1


除非在运行时动态编译代码,否则attrbute是不能更改的。

#2


用数组和指针就行了,那个成员定义成指针,指向一个动态分配的数组

#3


动态编译代码好像很烦啊,有没有其他思路能解决这个问题,我就是封送这个结构体给dll,但结构体里面的数组元素个数是不确定的。

#4


你直接传数组不就可以了,为什么要用结构体?

#5


2楼的用数组和指针,在C#怎么用,关键这个数组还要加上面那个属性啊,具体语法能不能给我举个例子

#6


这个结构体完整的应该是这样的
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct SASK  //股票报价返回
    {
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 603)]
        public Ask[] m_ask; //股票报价
        public int m_a;
        public byte m_b;
    }
然后转成C#的IntPtr类型 对应那边是void *info   C# void test(IntPtr info)  C++ void test(void * info)

#7


引用 5 楼 gxp402175383 的回复:
2楼的用数组和指针,在C#怎么用,关键这个数组还要加上面那个属性啊,具体语法能不能给我举个例子


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct SASK  //股票报价返回
        {
            
            public Ask* m_ask; //股票报价
            public int m_a;
            public byte m_b;
        }

        static void TestAsk()
        {
            SASK sa;
            var askList = new List<Ask>();
            //askList.add(xxxx);
            var asks=askList.ToArray();
            fixed (Ask* pask = asks)
            {
                sa.m_ask = pask;
                //调用函数......
            }
            
        }

#8


soaringbird  高手,如果这个方法可行,请问结构体里面public Ask* m_ask;  这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了

#9


引用 8 楼 gxp402175383 的回复:
soaringbird  高手,如果这个方法可行,请问结构体里面public Ask* m_ask;  这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了

你先把C++原型贴出来,确定一下怎么改写.
unsafe加在类、结构、方法的声明前面。在项目属性里还有一个开关,选上。

#10


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct SASK //股票报价返回
    {
     public intptr
    }

#11


引用 9 楼 soaringbird 的回复:
Quote: 引用 8 楼 gxp402175383 的回复:

soaringbird  高手,如果这个方法可行,请问结构体里面public Ask* m_ask;  这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了

你先把C++原型贴出来,确定一下怎么改写.
unsafe加在类、结构、方法的声明前面。在项目属性里还有一个开关,选上。


C++发送给服务器结构体: struct base
{
unsigned char a;
short b;
};

        struct AA: public base
{
unsigned short c;
BB d[603];
};

        struct BB
{
unsigned short e;
CC f;
};

        struct CC
{
unsigned char g;
char h[10];
};
调用的接口函数 sendmsg(void *msg)


C++从服务器接收的结构体:
     struct base
{
unsigned char a;
short b;
};

        struct DD: public base
{
unsigned short o;
EE p[603];
};

        struct EE
{
unsigned short q;
FF r;
};

        struct FF
{
unsigned char s;
char t[10];
};
接收的话给的是内存地址,通过Marshal.PtrToStructure来转,问题关键是接收和发送的两大结构体里面有个类型数组,譬如现在我写的 603这个大小,翻译成C#应该就是我在1楼写的SizeConst = 603。
问题就是 这个603是动态的,可能下次发送的大小是500或400。在C++里面,可以把它设置成1,然后动态申请n*sizeof(BB)的空间,请问C#要怎么使它成动态的

#12


引用 11 楼 gxp402175383 的回复:
Quote: 引用 9 楼 soaringbird 的回复:

Quote: 引用 8 楼 gxp402175383 的回复:

soaringbird  高手,如果这个方法可行,请问结构体里面public Ask* m_ask;  这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了

你先把C++原型贴出来,确定一下怎么改写.
unsafe加在类、结构、方法的声明前面。在项目属性里还有一个开关,选上。


C++发送给服务器结构体: struct base
{
unsigned char a;
short b;
};

        struct AA: public base
{
unsigned short c;
BB d[603];
};

        struct BB
{
unsigned short e;
CC f;
};

        struct CC
{
unsigned char g;
char h[10];
};
调用的接口函数 sendmsg(void *msg)


C++从服务器接收的结构体:
     struct base
{
unsigned char a;
short b;
};

        struct DD: public base
{
unsigned short o;
EE p[603];
};

        struct EE
{
unsigned short q;
FF r;
};

        struct FF
{
unsigned char s;
char t[10];
};
接收的话给的是内存地址,通过Marshal.PtrToStructure来转,问题关键是接收和发送的两大结构体里面有个类型数组,譬如现在我写的 603这个大小,翻译成C#应该就是我在1楼写的SizeConst = 603。
问题就是 这个603是动态的,可能下次发送的大小是500或400。在C++里面,可以把它设置成1,然后动态申请n*sizeof(BB)的空间,请问C#要怎么使它成动态的

先去了解一下在struct 里面数组如何存储的

#13


使用用数组和指针,把那个成员定义成指针,指向一个动态分配的数组应该就可以了

#14


引用 13 楼 u010483061 的回复:
使用用数组和指针,把那个成员定义成指针,指向一个动态分配的数组应该就可以了



能不能举一个例子啊,语法写上后有报错。

#15


BB  d[603];
这个在c++里是BB d[1]还是 BB*d  ?

#16


引用 15 楼 soaringbird 的回复:
BB  d[603];
这个在c++里是BB d[1]还是 BB*d  ?


在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

#17


引用 16 楼 gxp402175383 的回复:
Quote: 引用 15 楼 soaringbird 的回复:

BB  d[603];
这个在c++里是BB d[1]还是 BB*d  ?


在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

我怎么没见过这种用法,通常是用指针动态分配空间的

#18


该回复于2013-09-03 08:31:17被管理员删除

#19


引用 16 楼 gxp402175383 的回复:
Quote: 引用 15 楼 soaringbird 的回复:

BB  d[603];
这个在c++里是BB d[1]还是 BB*d  ?


在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

用intptr
传递的时候用Marshal.UnsafeAddrOfPinnedArrayElement 
如果你能确定尺寸,也可以用Marshal.AllocHGlobal

#20



在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教
我怎么没见过这种用法,通常是用指针动态分配空间的

它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做

#21


引用 19 楼 hdt 的回复:
Quote: 引用 16 楼 gxp402175383 的回复:

Quote: 引用 15 楼 soaringbird 的回复:

BB  d[603];
这个在c++里是BB d[1]还是 BB*d  ?


在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

用intptr
传递的时候用Marshal.UnsafeAddrOfPinnedArrayElement 
如果你能确定尺寸,也可以用Marshal.AllocHGlobal


你的意思是写成这样?
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct SASK
        {
            
            public intptr m_ask;
            public int m_a;
            public byte m_b;
        }

        static void TestAsk()
        {
            SASK sa;
            var askList = new List<Ask>();
            //askList.add(xxxx);
            var asks=askList.ToArray();
            fixed (Ask* pask = asks)
            {
                sa.m_ask = pask;
                //调用函数......
            }
            
        }

#22


引用 20 楼 gxp402175383 的回复:
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

我怎么没见过这种用法,通常是用指针动态分配空间的

它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做

难道是 BB d[1]; d=malloc(603*sizeof(BB)); 这样编译都过不了啊

#23


引用 22 楼 soaringbird 的回复:
Quote: 引用 20 楼 gxp402175383 的回复:


在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢  赐教

我怎么没见过这种用法,通常是用指针动态分配空间的


它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做

难道是 BB d[1]; d=malloc(603*sizeof(BB)); 这样编译都过不了啊

可以的,本来想贴出来,上次有个人qq发我的,一时找不到了,最终肯定是动态申请,malloc刚才我也有问题,是怎么个语法c++里有点不清楚了。

#24



struct AA
{
   int size;
   BB d[1];
};


在C++里面,之所有有BB d[1]这种写法,它表示至少有一个BB, 跟在一个size后面。因此在内存布局上,他们必须是 连续的。

struct Point
{
    int X, Y;
};

struct PointList
{
    int Length;
    Point Points[1];  //<--
};

extern "C" _declspec(dllexport) Point Sum(PointList& pointList)
{
    Point result = {};
    for(int i = 0; i < pointList.Length; i++)
    {
        result.X += pointList.Points[i].X;
        result.Y += pointList.Points[i].Y;
    }
    return result;
}

void Test()
{
    PointList* ptr = (PointList*)malloc(4 + sizeof(Point) * 3);
    ptr->Length = 3;

    ptr->Points[0].X = 1;
    ptr->Points[0].Y = 2;
    ptr->Points[1].X = 11;
    ptr->Points[1].Y = 22;
    ptr->Points[2].X = 111;
    ptr->Points[3].Y = 222;
    // ptr指向的内存为:  [3,1,2,11,22,111,222]

    Point sum = Sum(*ptr);  // sum.X=123, sum.Y=246
    free(ptr);
}


对C#来说,带有的关键就是内存布局的兼容,你可以用IntPtr,也可以用byte[],但是,要提供一段连续的内存[3,1,2,11,22,111,222]。例子可以这样写:

private void button1_Click(object sender, EventArgs e)
{
    Point[] points = new Point[]
    {
        new Point(1,2),
        new Point(11,22),
        new Point(111,222),
    };

    int int32InBytes = Marshal.SizeOf(typeof(int));
    int arrayInBytes = Marshal.SizeOf(typeof(Point)) * points.Length;

    // 写PointList.Length
    byte[] buffer = new byte[int32InBytes + arrayInBytes];
    BitConverter.GetBytes(points.Length).CopyTo(buffer, 0);

    // 写PointList.Points
    GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);
    Marshal.Copy(gc.AddrOfPinnedObject(), buffer, 4, buffer.Length - 4);
    gc.Free();

    Point sum = Sum(buffer);  // X=123, Y=246
}

[DllImport("xxx", CallingConvention = CallingConvention.Cdecl)]
extern static Point Sum(byte[] buffer);


#25


引用 24 楼 gomoku 的回复:

struct AA
{
   int size;
   BB d[1];
};


在C++里面,之所有有BB d[1]这种写法,它表示至少有一个BB, 跟在一个size后面。因此在内存布局上,他们必须是 连续的。

struct Point
{
    int X, Y;
};

struct PointList
{
    int Length;
    Point Points[1];  //<--
};

extern "C" _declspec(dllexport) Point Sum(PointList& pointList)
{
    Point result = {};
    for(int i = 0; i < pointList.Length; i++)
    {
        result.X += pointList.Points[i].X;
        result.Y += pointList.Points[i].Y;
    }
    return result;
}

void Test()
{
    PointList* ptr = (PointList*)malloc(4 + sizeof(Point) * 3);
    ptr->Length = 3;

    ptr->Points[0].X = 1;
    ptr->Points[0].Y = 2;
    ptr->Points[1].X = 11;
    ptr->Points[1].Y = 22;
    ptr->Points[2].X = 111;
    ptr->Points[3].Y = 222;
    // ptr指向的内存为:  [3,1,2,11,22,111,222]

    Point sum = Sum(*ptr);  // sum.X=123, sum.Y=246
    free(ptr);
}


对C#来说,带有的关键就是内存布局的兼容,你可以用IntPtr,也可以用byte[],但是,要提供一段连续的内存[3,1,2,11,22,111,222]。例子可以这样写:

private void button1_Click(object sender, EventArgs e)
{
    Point[] points = new Point[]
    {
        new Point(1,2),
        new Point(11,22),
        new Point(111,222),
    };

    int int32InBytes = Marshal.SizeOf(typeof(int));
    int arrayInBytes = Marshal.SizeOf(typeof(Point)) * points.Length;

    // 写PointList.Length
    byte[] buffer = new byte[int32InBytes + arrayInBytes];
    BitConverter.GetBytes(points.Length).CopyTo(buffer, 0);

    // 写PointList.Points
    GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);
    Marshal.Copy(gc.AddrOfPinnedObject(), buffer, 4, buffer.Length - 4);
    gc.Free();

    Point sum = Sum(buffer);  // X=123, Y=246
}

[DllImport("xxx", CallingConvention = CallingConvention.Cdecl)]
extern static Point Sum(byte[] buffer);



请问:
报了Object contains non-primitive or non-blittable data错误,在GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);这句话。
我的结构体在Point还有个自定义类型参数,是不是这个引起的, 没查出来,然后这个头还要不要写  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct Point
{
    int X, Y;
     TT _t;
};
public struct TT
{
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string str;
}