2

I am reading a binary file of a specific format, and am used to being able to cast a block of data to a struct then reading the struct to pull fields out of the binary datafile.

I'm trying to do this but failing in C#, they seem more like classes than structures in the C sense. Is it possible to do what I want? For example..

public struct Datum {
    byte type;
    ushort payload;
}

public struct DiskPage {
    ushort pageNumber;
    Datum[] data = Datum[170];
}

I want to be able to read 512 bytes of a file and cast it to a DiskPage, then to be able to read the values from the DiskPage structure. Is this possible in c# - or is there another preferred approach? Should I just leave that code in C and link it in?

Thanks! Reza

reza
  • 1,329
  • 2
  • 22
  • 37
  • I believe to do this exactly the way you're used to, this would require some sort of type punning, and in C# that would be unsafe code. You'd have to use pointers rather than references (if it is even possible at all). – Merlyn Morgan-Graham Sep 04 '11 at 20:37
  • 1
    forget what you know of C and learn C# the C# way – David Heffernan Sep 04 '11 at 20:39
  • It's possible - probably not a good idea. See Christopher Currens' answer on this StackOverflow question for how-to: http://stackoverflow.com/questions/7030150/copying-byte-array-to-various-fields-in-class-struct-in-c/7030285#7030285 – vcsjones Sep 04 '11 at 20:39
  • @David: good advice but there are still plenty of files and APIs with byte/bit layout around. – H H Sep 04 '11 at 20:48
  • I've redefined my structs and code to access it here: http://pastebin.com/3bKkW2mB – reza Sep 04 '11 at 22:00
  • I've redefined my structs and code to access it here: http://pastebin.com/3bKkW2mB However, the code gets to the call PtrToStructure() and then it returns without doing anything and it doesn't seem to throw an error. Thoughts? – reza Sep 04 '11 at 22:06

3 Answers3

4

The compiler doesn't respect ordering of your fields by default (also it might move the fields and leave gaps in the memory = Packing). By using StructLayout you can enforce a different behavior (Default, Sequential, or Explicit).

Use MarshalAs for specific options on a field. Be careful with endianess.

[StructLayout(LayoutKind.Explicit, Size=16, CharSet=CharSet.Ansi)]
public struct MySystemTime 
{
   [FieldOffset(0)]public ushort wYear; 
   [FieldOffset(2)]public ushort wMonth;
   [FieldOffset(4)]public ushort wDayOfWeek; 
   [FieldOffset(6)]public ushort wDay; 
   [FieldOffset(8)]public ushort wHour; 
   [FieldOffset(10)]public ushort wMinute; 
   [FieldOffset(12)]public ushort wSecond; 
   [FieldOffset(14)]public ushort wMilliseconds; 
}
Marcel Jackwerth
  • 53,948
  • 9
  • 74
  • 88
3

I suggest you read Mastering C# structs that discusses using marshaling (Marshal.Copy in particular) for that purpose.

Lior Ohana
  • 3,467
  • 4
  • 34
  • 49
  • Thanks! that was a great link and the code from that was also identical to code I found here: http://www.codeproject.com/KB/files/fastbinaryfileinput.aspx – reza Sep 04 '11 at 21:08
0

You can use fixed arrays in C# if you compile with Unsafe option enabled. You can also use pointers.

internal unsafe struct MyStruct
{
    public fixed byte MyFixedArray[128];
    public byte* MyPointer;
}

It is preferred to use marshalling, field offset and avoid unsafe code. Use unsafe code if you really need too in small portion of your code. Don't expose to external world a fixed array or a pointer (interfaces or public classes\structs) if you can avoid it.

Salvatore Previti
  • 8,956
  • 31
  • 37