2

I'm stuck on this one.

I'm reading a binary file which has te following format:

Field name  Size in bytes     Example
-------------------------------------
Date        19                1998_12_22 PM 20:15
Serial      4                 0001

Using the following struct and using the answers to this question I'm trying to read the file.

[StructLayout(LayoutKind.Explicit, Size=23, Pack = 1)]
struct MeasurementStruct
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)]
    [FieldOffset(0)]
    public string Date;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
    [FieldOffset(19)]
    public string Serial;
}

However, when instantiating the class that holds this struct I get an error at FieldOffset 19. Unfortunately, this error is in Dutch but it roughly translates to "Cannot load MeasurementStruct because field at off 19 is not aligned well (fields may overlap)".

I found out that changing the FieldOffset[19] to FieldOffset[20] makes the error disappear. However, 20 is not the right offset in my case, is it?

Community
  • 1
  • 1
Robbert Dam
  • 4,027
  • 10
  • 39
  • 58

4 Answers4

1

It seems that there is size problem between your data (23 bytes) and the size of structure (24 bytes). Is it normal ?

Update: The Pack=1 attribute should guarantee the memory alignment, but googling gives divergent response on structure's field alignment . What you can do is to read 23 bytes in a byte array, then extract the two strings with the Encoding class:

byte[] array = ... // read 23 bytes
String s1 = Encoding.ASCII.GetString(array, 0, 19);
String s2 = Encoding.ASCII.GetString(array, 19, 4); 
Laurent Etiemble
  • 27,111
  • 5
  • 56
  • 81
  • thanks for your answer. the struct I gave was just a simplified version of the file format. The actual format is a lot more bigger and complex, so encoding all fields one by one is not really an option – Robbert Dam Dec 11 '09 at 13:10
1

None of the answers where exactly what I'm looking for, but I found a better approach myself by defining the struct als follows.

[StructLayout(LayoutKind.Sequential, Size = MeasurementStructSize, Pack = 1)]
struct MeasurementStruct
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)]
    public string Date;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
    public string SerialNumber;

}

I changed LayoutKind to Sequential. In that case, the Pack field actually has a meaning and I don't need to add the FieldOffsets. The above works fine.

Thanks anyway all of you!

Robbert Dam
  • 4,027
  • 10
  • 39
  • 58
0

20 is probably the correct offset for this architecture. The compiler will pad with zeroes to put struct members on even locations. Exact "how even" is architecture and compiler depending, but it has to be a multiple of 4 in 32bit architectures if I'm not mistaken.

For example, the following struct:

struct MyStruct
{
  char ch;  // Offset 0
            // 3 "invisible" bytes padding inserted by the compiler
  int i;    // Offset 4
}
Isak Savo
  • 34,957
  • 11
  • 60
  • 92
0

Could be that string requires 2 bytes per character (unicode), read as a byte array and use ASCIIEncoding to convert to string

MaLio
  • 2,498
  • 16
  • 23