C# StructLayout.Explicit 问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1182782/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# StructLayout.Explicit Question
提问by Taylor Leese
I'm trying to understand why the second example below works with no issues, but the first example gives me the exception below. It seems to me that both examples should give an exception based on the description. Can anyone enlighten me?
我试图理解为什么下面的第二个例子没有问题,但第一个例子给了我下面的例外。在我看来,这两个例子都应该根据描述给出一个例外。任何人都可以启发我吗?
Unhandled Exception: System.TypeLoadException: Could not load type 'StructTest.OuterType' from assembly 'StructTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field.
at StructTest.Program.Main(String[] args) Press any key to continue . . .
未处理的异常:System.TypeLoadException:无法从程序集“StructTest,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”中加载类型“StructTest.OuterType”,因为它在偏移量 0 处包含一个对象字段,该字段未正确对齐或重叠通过非对象字段。
在 StructTest.Program.Main(String[] args) 按任意键继续。. .
Example 1
示例 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StructTest
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct InnerType
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
char[] buffer;
}
[StructLayout(LayoutKind.Explicit)]
struct OuterType
{
[FieldOffset(0)]
int someValue;
[FieldOffset(0)]
InnerType someOtherValue;
}
class Program
{
static void Main(string[] args)
{
OuterType t = new OuterType();
System.Console.WriteLine(t);
}
}
}
Example 2
示例 2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StructTest
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct InnerType
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
char[] buffer;
}
[StructLayout(LayoutKind.Explicit)]
struct OuterType
{
[FieldOffset(4)]
private int someValue;
[FieldOffset(0)]
InnerType someOtherValue;
}
class Program
{
static void Main(string[] args)
{
OuterType t = new OuterType();
System.Console.WriteLine(t);
}
}
}
采纳答案by Mehrdad Afshari
The common language runtime contains a verifier that makes sure the running code (verifiable IL) cannot possibly corrupt memory in the managed environment. This prevents you to declare such a structure in which fields overlap. Basically, your struct contains two data members. One integer (which is 4 bytes) and a native integer (pointer size). On a 32 bit CLR, in which you are probably running your code, the char[]
will take 4 bytes so if you put the integer less than four bytes away from the beginning of the struct, you'll have overlapping fields. It's interesting to note that both of your code snippets with fail on a 64 bit runtime, as the pointer size is 8 bytes.
公共语言运行时包含一个验证器,可确保运行的代码(可验证的 IL)不可能破坏托管环境中的内存。这可以防止您声明这样一个字段重叠的结构。基本上,您的结构包含两个数据成员。一个整数(4 个字节)和一个本机整数(指针大小)。在 32 位 CLR 上,您可能正在其中运行您的代码,char[]
它将占用 4 个字节,因此如果您将整数放在距结构开头少于 4 个字节的位置,您将有重叠的字段。有趣的是,您的两个代码片段在 64 位运行时都失败了,因为指针大小为 8 字节。
回答by Taylor Leese
I figured I'd respond with the solution I used to create the union -- which was my original intention. I used an unsafe struct and a fixed array and then used a property to interact with the fixed array. I believe this should do what I want.
我想我会用我用来创建联合的解决方案来回应——这是我的初衷。我使用了一个不安全的结构和一个固定数组,然后使用一个属性与固定数组交互。我相信这应该做我想做的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StructTest
{
[StructLayout(LayoutKind.Explicit)]
unsafe struct OuterType
{
private const int BUFFER_SIZE = 100;
[FieldOffset(0)]
private int transactionType;
[FieldOffset(0)]
private fixed byte writeBuffer[BUFFER_SIZE];
public int TransactionType
{
get { return transactionType; }
set { transactionType = value; }
}
public char[] WriteBuffer
{
set
{
char[] newBuffer = value;
fixed (byte* b = writeBuffer)
{
byte* bptr = b;
for (int i = 0; i < newBuffer.Length; i++)
{
*bptr++ = (byte) newBuffer[i];
}
}
}
get
{
char[] newBuffer = new char[BUFFER_SIZE];
fixed (byte* b = writeBuffer)
{
byte* bptr = b;
for (int i = 0; i < newBuffer.Length; i++)
{
newBuffer[i] = (char) *bptr++;
}
}
return newBuffer;
}
}
}
class Program
{
static void Main(string[] args)
{
OuterType t = new OuterType();
System.Console.WriteLine(t);
}
}
}