如何使用指针重新解释结构?

时间:2019-07-05 06:02:08

标签: c#

我正在将一些C ++代码转换为C#。我想将字节数组重新解释为结构,就像在C ++中可以轻松做到的那样。 我宁愿避免序列化或反射,而只使用指针,我想知道这是否可能。

这是我要从文件重新解释的结构:

public struct MS_DOS_Stub
{
    UInt16 e_magic;                     // Magic number
    UInt16 e_cblp;                      // Bytes on last page of file
    UInt16 e_cp;                        // Pages in file
    UInt16 e_crlc;                      // Relocations
    UInt16 e_cparhdr;                   // Size of header in paragraphs
    UInt16 e_minalloc;                  // Minimum extra paragraphs needed
    UInt16 e_maxalloc;                  // Maximum extra paragraphs needed
    UInt16 e_ss;                        // Initial (relative) SS value
    UInt16 e_sp;                        // Initial SP value
    UInt16 e_csum;                      // Checksum
    UInt16 e_ip;                        // Initial IP value
    UInt16 e_cs;                        // Initial (relative) CS value
    UInt16 e_lfarlc;                    // File address of relocation table
    UInt16 e_ovno;                      // Overlay number
    #region ReservedWords          
    UInt16 e_res1;                      // Reserved words
    UInt16 e_res2;                      //Cant initialize an array in a struct in C#
    UInt16 e_res3;
    UInt16 e_res4;
    #endregion                      
    UInt16 e_oemid;                     // OEM identifier (for e_oeminfo)
    UInt16 e_oeminfo;                   // OEM information; e_oemid specific
    #region ReservedWords2
    UInt16 e_res5;                      // Reserved words
    UInt16 e_res6;
    UInt16 e_res7;
    UInt16 e_res8;
    UInt16 e_res9;
    UInt16 e_res10;
    UInt16 e_res11;
    UInt16 e_res12;
    UInt16 e_res13;
    UInt16 e_res14;
    #endregion                                      // Reserved words
    UInt32 e_lfanew;                    // File address of new exe header 
};

这是我正在调用的方法:

static unsafe Dictionary<string, UInt32> dumpSymbols(ref byte[] bin)
{
    fixed (byte* pBin = bin)
    {
        MS_DOS_Stub* stub = (MS_DOS_Stub*)(pBin);

        if(stub->e_magic != IMAGE_DOS_SIGNATURE)
        {
            throw new FileLoadException("Error, Invalid file. DOS Signature is incorrect.");
        }

        // ...

    }
    return null;
}

我希望能够简单地使用stub->memberstub.member,但是存根似乎没有成员。

1 个答案:

答案 0 :(得分:0)

一件事是,当您像声明结构一样声明结构时,结构的所有成员都变为私有。因此,从外部看它似乎没有成员。这很容易解决,只需在每个成员声明之前添加public

struct MS_DOS_Stub
{
    public UInt16 e_magic;                     // Magic number
    // and so on and so forth

将字节数组重新解释为结构是另一回事。据我了解,您从文件中读取数据作为字节数组,然后将其转换为结构。您的代码,尤其是这部分

fixed (byte* pBin = bin)
{
    MS_DOS_Stub* stub = (MS_DOS_Stub*)(pBin);

对我不好。不仅因为它使用了指针,这不是C#可以做的最好的事情。如果考虑到这一点,则此方法(无论是否以C#或C ++实现)都依赖于内存中的结构布局,小端/大端架构。通常,您不能将内存的一部分转储到文件中然后再读回(可能在另一台计算机上!),并期望它是结构的正确表示。

我不知道此解决方案既简单又健壮。在您的情况下,我将只使用BitConverter来逐一提取我所迷惑的结构的各个部分。喜欢

stub.magic = BitConverter.ToInt16(bin, 0);
stub.e_cblp = BitConverter.ToInt16(bin, 2);
.....
stub.e_lfanew = BitConverter.ToInt32(bin, 60);

对于一个简单的任务,此代码可能很长且很冗长,但是可以保证不管您的环境如何,它都可以工作。而且,这样一来,您就不会有任何unsafe指针欺骗的代码,如果您使用.Net进行编程,这是一件好事。