Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#获取结构偏移量的命令?_C# - Fatal编程技术网

C#获取结构偏移量的命令?

C#获取结构偏移量的命令?,c#,C#,假设我有这样一个C#结构: [StructLayout(LayoutKind.Explicit)] struct IMAGE_DOS_HEADER { [FieldOffset(60)] public int e_lfanew; } byte[] data = new byte[4096]; FileStream f = new FileInfo(filename).Open(FileMode.Open, FileAccess.Read); int n = f.Read(data, 0

假设我有这样一个C#结构:

[StructLayout(LayoutKind.Explicit)]
struct IMAGE_DOS_HEADER {
    [FieldOffset(60)] public int e_lfanew;
}
byte[] data = new byte[4096];
FileStream f = new FileInfo(filename).Open(FileMode.Open, FileAccess.Read);
int n = f.Read(data, 0, 4096);
if (n >= offsetof(IMAGE_DOS_HEADER.e_lfanew) + sizeof(int)) {
    ...
}
现在假设我从一个文件中读取数据,如下所示:

[StructLayout(LayoutKind.Explicit)]
struct IMAGE_DOS_HEADER {
    [FieldOffset(60)] public int e_lfanew;
}
byte[] data = new byte[4096];
FileStream f = new FileInfo(filename).Open(FileMode.Open, FileAccess.Read);
int n = f.Read(data, 0, 4096);
if (n >= offsetof(IMAGE_DOS_HEADER.e_lfanew) + sizeof(int)) {
    ...
}
现在我想测试
n
,以确保我已经读取了足够的字节来重新获得
e\u lfanew
的值。有没有办法不用重新键入就可以得到值60(FieldOffset)?我在找这样的东西:

[StructLayout(LayoutKind.Explicit)]
struct IMAGE_DOS_HEADER {
    [FieldOffset(60)] public int e_lfanew;
}
byte[] data = new byte[4096];
FileStream f = new FileInfo(filename).Open(FileMode.Open, FileAccess.Read);
int n = f.Read(data, 0, 4096);
if (n >= offsetof(IMAGE_DOS_HEADER.e_lfanew) + sizeof(int)) {
    ...
}

有这样的命令吗?在我的实际代码中,我必须进行几个这样的测试,手动键入数字似乎很乏味,而且容易出错,方法是将结构中先前的字段相加,或者从FieldOffset属性中复制值。有更好的方法吗?

是的,您可以使用反射来实现这一点

FieldOffsetAttribute fieldOffset = 
    (FieldOffsetAttribute)typeof(IMAGE_DOS_HEADER)
        .GetField("e_lfanew")
        .GetCustomAttributes(
            typeof(FieldOffsetAttribute),
            true
        )[0];
Console.WriteLine(fieldOffset.Value);
您甚至可以将其转化为一种很好的方法:

static int FieldOffset<T>(string fieldName) {
    if (typeof(T).IsValueType == false) {
        throw new ArgumentOutOfRangeException("T");
    }
    FieldInfo field = typeof(T).GetField(fieldName);
    if (field == null) {
        throw new ArgumentOutOfRangeException("fieldName");
    }
    object[] attributes = field.GetCustomAttributes(
        typeof(FieldOffsetAttribute),
        true
    );
    if (attributes.Length == 0) {
        throw new ArgumentException();
    }
    FieldOffsetAttribute fieldOffset = (FieldOffsetAttribute)attributes[0];
    return fieldOffset.Value;
}
static int FieldOffset(字符串字段名){
if(typeof(T).IsValueType==false){
抛出新ArgumentOutOfRangeException(“T”);
}
FieldInfo field=typeof(T).GetField(fieldName);
如果(字段==null){
抛出新ArgumentOutOfRangeException(“fieldName”);
}
对象[]属性=field.GetCustomAttributes(
类型(FieldOffsetAttribute),
真的
);
如果(attributes.Length==0){
抛出新ArgumentException();
}
FieldOffsetAttribute fieldOffset=(FieldOffsetAttribute)属性[0];
返回fieldOffset.Value;
}
用法:

Console.WriteLine(FieldOffset<IMAGE_DOS_HEADER>("e_lfanew"));
Console.WriteLine(FieldOffset(“e_lfanew”);

嗯,您已经在结构声明中使用了一个幻数。不妨这样做:

private const int LfaNewOffset = 60;

[StructLayout(LayoutKind.Explicit)]
struct IMAGE_DOS_HEADER {
    [FieldOffset(LfaNewOffset)] public int e_lfanew;
}
...
if (n >= LfaNewOffset + sizeof(int)) {
    ...
}
使用Marshal.OffsetOf:

Marshal.OffsetOf(typeof(IMAGE_DOS_HEADER), "e_lfanew")

+我同意。反射是解决这个问题的最安全(确定性和可维护性)的方法。在避免代码重复的上下文中,定义常量(正如nobugz所建议的)几乎总是比使用反射更好的选择。在某些情况下,反射是适当的,但避免代码重复通常可以通过其他方式完成。也就是说,反思可能更简单,因为有很多这样的数字。注:我不是向下投票人。@Brian:不清楚他是否有权访问结构的定义。如果他这样做,我同意。如果他没有,则需要另一种方法。@Jason:现在,在看到wj32的答案后,我觉得你的答案在这种情况下过于复杂了。@Brian:请看我对wj32答案的评论。如果他无法访问结构的定义怎么办?我同意,他到底做还是不做还不清楚。@Jason:如果他不做,那么这就行不通了。但是我不认为有必要指出这是这个方法的一个缺陷,因为它是不言而喻的。哇,这正是他所要求的(尽管我仍然对nobugz的答案感到更舒服,假设它是可行的)<代码>封送处理用于在托管和非托管之间切换。因此,从文档中“
offset of
提供了非托管结构布局的偏移量,它不一定对应于托管结构布局的偏移量。”因此在某些情况下,这可能给出错误的答案。您为什么想知道托管结构的偏移量?即使您知道您将无法以任何方式使用它,因为即使获得指向该结构的指针,也意味着它是可轻击的。你的观察与任何实际目的都完全无关。这适用于问题中的具体情况。一般来说,这是行不通的。例如,如果您有一个包含一个或多个bool类型字段的结构,则sizeof(bool)==1,但Marshal.sizeof(type(bool))=4。从Marshal.OffsetOf开始,偏移量也同样不正确。换句话说,Marshal.OffsetOf函数给出的是封送结构的非托管偏移量,这可能不同于非封送偏移量。Marshal.OffsetIf是否可以用于结构的结构中的字段/道具?这需要如何命名?比如说:Struct1.Struct2.Prop1 Strct1中Prop1的标识符是什么?哇,我没想到我会得到任何真正的答案(除了nobugz的),这里我有三个选择!我几乎不知道该选哪个,所以我把他们全都投了赞成票。简单地定义常量是一种合理的方法,但它混淆结构布局的方式有点烦人。我仍在学习托管/非托管的微妙之处,但我认为wj32是正确的,因为编译器已经允许我获取指向结构的指针,我知道托管/非托管的offet是相同的。所以我选择他的答案,因为它似乎产生了最容易阅读的代码。谢谢大家这么好的回复!