2017-01-04 12 views
0

私はc apiと.netアプリケーションの間にいくつかのグルーコードを書いています。 C#構造体を書くためには、ここで実際に何が起こっているのかを理解する必要があります。cで構造体が「整列」されているとはどういう意味ですか?

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct CommonDialogBaseParam { 
    public ulong size; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=36)] 
    public string reserved; 
    public uint magic; 
} 

言うまでもないが、上の私は本当に「予約」や「魔法」のいずれかへの適切なアクセスを必要としない...と言って、次のように

typedef struct CommonDialogBaseParam { 
    size_t size; 
    uint8_t reserved[36]; 
    uint32_t magic; 
} CommonDialogBaseParam __attribute__ ((__aligned__(8))); 

// Somewhere else 
#define __attribute__(x) 

私はC#の同等のものを書くように誘惑していますC#の側ですが、メンバーを適切に保存する必要があります。

+1

問題はなんですか? – Guy

+0

私は、__aligned __(8)が構造体のメモリレイアウトを変更するので、C#側で同等の変更を加えなければならないと心配していますが、この場合はどのように整列したのかわかりません。 – Steinbitglis

+0

さて、 '__attribute__'は何も定義されていないので、何も起こっていません;-)。 gcc定義である可能性があります。 –

答えて

1

これは、構造の最小位置合わせを8バイトに指定するGCC属性です。ドキュメントは次の場所にあります:https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#Common-Type-Attributes

これはこれらの構造体の割り当てに影響を与えますが、構造体自体のオフセットには影響しません。しかし、それは、ネイティブ構造が最終メンバの後に余分なパディングを持つ可能性があることを意味します。

これに相当するものはC#であり、ネイティブコードが構造体と何をするかによって問題が発生する可能性があります。構造体がC#コードによって割り当てられている場合、構造が整列していない可能性がありますが、それは正確性ではなくパフォーマンスにのみ影響します。ネイティブコードが構造体のコピーを作成すると、構造体の最後にあるパディングを読み込もうとします。おそらくアクセス違反につながる可能性があります。私の推測では、p/invokeで使用されるヒープ・アロケータは少なくとも8のブロック・サイズのチャンクにメモリーを割り当てますので、これを避けることができます。しかし、私はあなたがこれに頼ることができるかどうか疑問に思います。

はさておき、このパディングを残して、私はこのようなあなたの構造体を翻訳します:私はUIntPtrsize_tをマッピングした

[StructLayout(LayoutKind.Sequential)] 
public struct CommonDialogBaseParam { 
    public UIntPtr size; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=36)] 
    public byte[] reserved; 
    public uint magic; 
} 

注意、符号なしポインタサイズの値。個人的には、reservedフィールドにはbyte[]が好きです。これは、私が知る限り、Cコードにもっと真実を感じます。

あなた構造は、あなたが最後に余分なフィールドを追加することができる十分な大きさになることを確認したい場合は、次の

[StructLayout(LayoutKind.Sequential)] 
public struct CommonDialogBaseParam { 
    public UIntPtr size; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=36)] 
    public byte[] reserved; 
    public uint magic; 
    private uint padding; 
} 

この構造体に含まれているタイプのどれが8よりも大きいサイズを持っていないので、

[StructLayout(LayoutKind.Sequential, Pack=8)] 
public struct CommonDialogBaseParam { 
    public UIntPtr size; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=36)] 
    public byte[] reserved; 
    public uint magic; 
} 

をしかし、これには注意が:、あなたは所望の効果を達成するためにStructLayoutPackオプションを乱用ことができます。ネイティブコードは構造体を整列させます。上記のC#宣言は構造体を整列させ、そのメンバの整列を指定します。ここでは、メンバーの配置には影響しませんが、必ずしもそうではありません。

少し不満足です。

+0

うーん...「マジック」は4バイト先にプッシュされないので、8バイト境界で開始されますか? – Steinbitglis

+0

いいえ、そうではありません。私がリンクしているドキュメントはそのことを示唆していません。 –

+0

8バイトの配置が32ビットWindows上の構造体のサイズに影響しませんか?私。構造体のCバージョンでは、サイズ44からサイズ48に切り上げるために最後に4バイトの隠しパディングがありませんか? –

関連する問題