Structure alignment struggle.

A

A n g l e r

Hi all.


I've got the following code as a part of managed C++ library that is
loaded by a project in C#:

public ref class FlyCaptureEnumsAndStructsManaged
{
public:
typedef enum class FlyCaptureCameraModel { blabla, blabla2 };
typedef enum class FlyCaptureCameraType { blabla, blablabla, blamax =
0x7FFFFFFF };

[StructLayout(LayoutKind::Explicit, Pack=1 Size=2028)]
typedef ref struct FlyCaptureInfoEx
{
[FieldOffset(0)] int SerialNumber;
[FieldOffset(4)] FlyCaptureCameraType CameraType;
[FieldOffset(8)] FlyCaptureCameraModel CameraModel;
[FieldOffset(12), MarshalAs(UnmanagedType::ByValTStr, SizeConst=512)]
String^ pszModelName;

... blablabla
};
};

Now, I'm facing some alignment issue after this has been ported to x64
platform. I used to work with windows x86 and VS 2005, now am working
with VS 2008 and XP x64.

It looks that the offset FieldOffset(12) is for some reason treated as
an inappropriate layout as raised exceptions indicate this clearly. When
It definitely helps when I amend the offset position to FieldOffset(16).
I'm a bit puzzled cos I've tried to force alignment with Pack=1 and
Pack=4, though it still acts like it was specified Pack=8.

Just to stress out as well that the same structure built directly in C#
(even without specifying the pack size) seems to have the desired 4 byte
layout.


Do you have any clue what is going on here? Perhaps this all is down to
some compiler switches?


Thanks a lot,
Peter.
 
J

Jeff Winn

It would have helped a lot more if you hadn't removed part of the struct
definition.

I'm having a bit of trouble understanding why you're explicitly defining the
field offsets for the types involved. You've manually specified the
locations where they would be at normally simply using a sequential layout,
but I can't tell for sure since you decided to partially show us the struct.

Also according to the docs (unless I'm interpreting them incorrectly), the
pack property only works when you've specified Sequential for the layout.
http://msdn.microsoft.com/en-us/lib...teropservices.structlayoutattribute.pack.aspx

What you've shown us the equivalent of: I have a problem with this method,
it's throwing an object null reference exception. Why?
void DoSomething() {
int x = 0;
...
}
 
G

Göran Andersson

A said:
Hi all.


I've got the following code as a part of managed C++ library that is
loaded by a project in C#:

public ref class FlyCaptureEnumsAndStructsManaged
{
public:
typedef enum class FlyCaptureCameraModel { blabla, blabla2 };
typedef enum class FlyCaptureCameraType { blabla, blablabla, blamax
= 0x7FFFFFFF };

[StructLayout(LayoutKind::Explicit, Pack=1 Size=2028)]
typedef ref struct FlyCaptureInfoEx
{
[FieldOffset(0)] int SerialNumber;
[FieldOffset(4)] FlyCaptureCameraType CameraType;
[FieldOffset(8)] FlyCaptureCameraModel CameraModel;
[FieldOffset(12), MarshalAs(UnmanagedType::ByValTStr,
SizeConst=512)] String^ pszModelName;

What do you have here? What is the FielfOffset of the next member?

In x64, the pointers are 8 bytes instead of 4 bytes. If you have placed
the next member at 16, the pointer would overlap it.
 
A

A n g l e r

I'm having a bit of trouble understanding why you're explicitly defining
the field offsets for the types involved. You've manually specified the
locations where they would be at normally simply using a sequential
layout, but I can't tell for sure since you decided to partially show us
the struct.

Well, I've just replaced this all with Sequential and now it turns out
to work fine. The reason why I have it declared likewise is that
Sequential layout didn't seem to work fine on my previous machine and VS
2005 :d I have no clue what was the reason.
Also according to the docs (unless I'm interpreting them incorrectly),
the pack property only works when you've specified Sequential for the
layout.
http://msdn.microsoft.com/en-us/lib...teropservices.structlayoutattribute.pack.aspx

Yep, you're right. I've also spotted this. Any reason why Explicit
layout doesn't work as aligned every 4 bytes on x64?

Thanks,
Peter
 
A

A n g l e r

What do you have here? What is the FielfOffset of the next member?

In x64, the pointers are 8 bytes instead of 4 bytes. If you have placed
the next member at 16, the pointer would overlap it.


Erm, first three fields aren't pointers. The forth one has to do with
pointers, though I don't get why it needs to be aligned every 8 bytes
unless it's actual position is calculated with respect to the end of the
structure rather than the beginning. Perhaps I misapprehend some aspects
of this sort of layout, though Sequential doesn't force me to have 8
bytes alignment and works fine ... So, what is the little trick in it?

Cheers,
Peter.
 
J

Jeff Winn

Explictly defining the layout for members of structures determine where in
the structs the members get serialized based on the position from the start
of the struct. Also, FYI, you don't need to specify sequential for the
layout since it's the default setting for structs.

[StructLayout(LayoutKind.Explicit)]
struct MyStruct {
[FieldOffset(0)]
public int A;

[FieldOffset(4)]
public int B;

[FieldOffset(8)]
public IntPtr C;

[FieldOffset(12)]
public int D;
}

The Int32 type is 4 bytes wide, which is why the offset is 4 bytes apart.
However, since the C member is a pointer - on a 32 bit system this would be
4 bytes wide, whereas on a 64 bit system it is 8 bytes wide. So, if you're
explicitly defining the field positions and you move the application to a 64
bit system you can see that D would be in the wrong position as it would
actually need to be at offset 16.

Glad you got everything working. Happy to help :)
 
A

A n g l e r

Jeff, yes, though this still doesn't answer my question which is why
Sequential offset doesn't require such alignment? What is the actual
difference in representing both types of structures on a system level?

Cheers,
P.
 
G

Göran Andersson

A said:
Erm, first three fields aren't pointers. The forth one has to do with
pointers, though I don't get why it needs to be aligned every 8 bytes
unless it's actual position is calculated with respect to the end of the
structure rather than the beginning. Perhaps I misapprehend some aspects
of this sort of layout, though Sequential doesn't force me to have 8
bytes alignment and works fine ... So, what is the little trick in it?

Cheers,
Peter.

The third member isn't a pointer? I don't do any development in C++
these days, so I don't know exactly what the types translates into...

You are mixing layout attributes with marshalling attributes, perhaps
that's the problem? Layout attributes are used by the CLR to layout the
managed data, while marshalling attributes are used by the marshalling
methods when the data is copied into an unmanaged data structure.
 
A

A n g l e r

The third member isn't a pointer? I don't do any development in C++
these days, so I don't know exactly what the types translates into...

The forth one from my example is pointer - at least as long as I'm of a
sound mind ;)
You are mixing layout attributes with marshalling attributes, perhaps
that's the problem? Layout attributes are used by the CLR to layout the
managed data, while marshalling attributes are used by the marshalling
methods when the data is copied into an unmanaged data structure.

Erm, ok, though this seems to be a sleek way of passing unmanaged
structure with strings to C# environment ...
 
J

Jeff Winn

There is no difference in the structure itself, the difference is how the
marshaller handles the struct. When the members are laid out sequentially
(LayoutKind.Sequential) you're telling .NET to handle the marshalling for
you for that struct. It will determine where the members need to go when
it's marshalling them back and forth. If you're using an explicit layout
with field offsets for the members, you're telling the marshaller where it
should look for the data.

This would be what the struct looks like on a 32 bit system.

A B C D
00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00
0 4 8 12

And this would be the same struct represented on a 64 bit system.

A B C
D
00 00 00 00 | 00 00 00 00 | 00 00 00 00 00 00 00 00 | 00 00 00 00
0 4 8 -12-
16

With the example I wrote earlier, it's basically telling the marshaller to
look for the D field at position 12 of the array, which would be the last 4
bytes of the pointer used by the C field. I've rarely needed to use an
explicit layout for a struct. If I remember the last time I needed one I was
having to store 2 different objects at the same position within the struct.
Probably was from a union inside the struct defintion I was using in the
Win32 API.

Generally speaking you shouldn't use explicit layouts unless you absolutely
have to. They can cause a lot of problems when using different platforms.

A n g l e r said:
Jeff, yes, though this still doesn't answer my question which is why
Sequential offset doesn't require such alignment? What is the actual
difference in representing both types of structures on a system level?

Cheers,
P.
Explictly defining the layout for members of structures determine where
in the structs the members get serialized based on the position from the
start of the struct. Also, FYI, you don't need to specify sequential for
the layout since it's the default setting for structs.

[StructLayout(LayoutKind.Explicit)]
struct MyStruct {
[FieldOffset(0)]
public int A;

[FieldOffset(4)]
public int B;

[FieldOffset(8)]
public IntPtr C;

[FieldOffset(12)]
public int D;
}

The Int32 type is 4 bytes wide, which is why the offset is 4 bytes apart.
However, since the C member is a pointer - on a 32 bit system this would
be 4 bytes wide, whereas on a 64 bit system it is 8 bytes wide. So, if
you're explicitly defining the field positions and you move the
application to a 64 bit system you can see that D would be in the wrong
position as it would actually need to be at offset 16.
 
Top