C#怎么实现union类型啊

maomiaomi 2011-03-31 10:49:50
小弟初涉c#,碰到一些问题想请教下

对于c++来说,定义一个union

union testunion
{
double a[3];
double b;
};
testunion aaaa;
aaaa.a[0]=100;
aaaa.a[1]=2;
cout<<sizeof(aaaa)<<" "<<aaaa.b<<endl;

可以得出sizeof(aaaa)结果为24,aaaa.b结果为100
也就是说b和a[0]是共享一块内存的

而在c#里面

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto)]
struct testunion
{
[FieldOffset(0),MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public double[] a;
[FieldOffset(8)]
public double b;
}
testunion aaaa=new testunion();
aaaa.a=new double[]{1,2,3};
Console.WriteLine(Marshal.SizeOf(aaaa)+"\t"+aaaa.b);

得到的结果是24和0,并不是预想中的2,也就是说b和a[1]并不是共享一块内存的

那调用dll的时候,他们之间的数据是怎么传送的呢?还是我的试验方法有问题?
...全文
821 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
maomiaomi 2011-04-02
  • 打赏
  • 举报
回复

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto)]
struct testunion
{
[FieldOffset(0),MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public double[] a;
[FieldOffset(8)]
public double b;
}

可是实际上调用dll的时候,a[1]和b的值是相等的
莫非是接受数据的时候对它进行了转换?
maomiaomi 2011-03-31
  • 打赏
  • 举报
回复
没人回啊标题不吸引人吗
ShinNakoruru 2011-03-31
  • 打赏
  • 举报
回复
现在的关键问题不在于内存对齐
而是在C#里声明一个double[]等于是声明了一个Array类的对象,这样结构体里保存的就是对象的引用,虽然Marshal.SizeOf返回仍然是24,但那是CLR将ManagedType转化为Unmanaged以后的结果,一旦你再声明一个Offset是0的字段,就会因为内存重叠覆盖掉引用类型而出错——无法加载,更谈不上ManagedType转化Unmanaged。

要么罗列出值类型字段,不用Array
要么想办法以unsafe代码解决
maomiaomi 2011-03-31
  • 打赏
  • 举报
回复
汗楼上的错了应该是这样

union testunion
{
double a[3];
double c;
double b[2];
};
testunion aaaa;
aaaa.a[0]=100;
aaaa.a[1]=2;
cout<<sizeof(aaaa)<<" "<<aaaa.b[1]<<endl;

这个b[1]和c#里面的b偏移量是相同的
maomiaomi 2011-03-31
  • 打赏
  • 举报
回复
谢谢楼上各位的回复

[FieldOffset(0)]
float f1;
[FieldOffset(0)]
float f2;
[FieldOffset(0)]
double d;

这个确实能解决问题,
可是我在网上查到的好多资料都是

[FieldOffset(0),MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public double[] a;

这样解决的
不必纠结于对齐没对齐

union testunion
{
double a[3];
double c;
double b;
};
testunion aaaa;
aaaa.a[0]=100;
aaaa.a[1]=2;
cout<<sizeof(aaaa)<<" "<<aaaa.b<<endl;

这样的话b就和c#里面的b一样了
ShinNakoruru 2011-03-31
  • 打赏
  • 举报
回复
推荐你
[FieldOffset(0)]
float f1;
[FieldOffset(0)]
float f2;
[FieldOffset(0)]
double d;

就这样定义
如果定义成数组,那就变成对象的引用了
烈火蜓蜻 2011-03-31
  • 打赏
  • 举报
回复
double[] a
是一个引用,
ShinNakoruru 2011-03-31
  • 打赏
  • 举报
回复
哦,忽然想起来了,你这个问题实际上是这样
你定义的
public double[] a
事实上是一个对象,也就是说struct里对应的只有一个指针,结果自然不对

thoughter 2011-03-31
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 shinnakoruru 的回复:]

怎么会一样呢
union testunion
{
double a[3];
double b;
};

这样定义的话, a[0]的内存偏移和b的内存偏移都是0
如果.net不允许定义两个字段的偏移相同,那可能还真没办法了
[/Quote]
两个字段可以相同 ,关键是有了对象double a[3];就会报错了

[FieldOffset(0)]
float f1;
[FieldOffset(32)]
float f2;
[FieldOffset(0)]
double d;
没问题

再加条
[FieldOffset(0),MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public double[] a;
就有问题了

建议用c/c++的dll
ShinNakoruru 2011-03-31
  • 打赏
  • 举报
回复
怎么会一样呢
union testunion
{
double a[3];
double b;
};

这样定义的话, a[0]的内存偏移和b的内存偏移都是0
如果.net不允许定义两个字段的偏移相同,那可能还真没办法了
maomiaomi 2011-03-31
  • 打赏
  • 举报
回复
定义b的FieldOffset为0会报错,所以定义为8了,但是如果内存是像c++那样构造的话,8和0是一样的
ShinNakoruru 2011-03-31
  • 打赏
  • 举报
回复
虽然我没去验证,但你要实现union的效果,起码要定义b的FieldOffset为0吧?

111,125

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧