2017-01-04 17 views
0

私は基本的に異なるMarshal.SizeOf()sizeof()の違いがわかっています。しかし、IntPtrの場合、両方とも常にはCPUアーキテクチャに関係なくまったく同じものを返しますか?Marshal.SizeOf(typeof(IntPtr))とsizeof(IntPtr)

+0

あなたは(64倍)4' 'それはどちらか常に何(32X)を意味または' 8'ますか?あなたは 'IntPtr'構造体がもっと管理されたメモリ(https://ericlippert.com/2013/06/13/whats-the-difference-sizeof-and-marshal-sizeof/)を必要としないのは幸いですいつか、またはプラットフォームによっては、適切なものを使い続ける方がよいでしょう。 – Sinatr

+0

メモリ内のサイズとワイヤのサイズが同じであるかどうかを気にする理由を説明できますか?あなたはトリビアの質問をしているだけですか、またはあなたの質問には何らかの目的がありますか? –

+0

@EricLippert主に、特にIntPtrを念頭に置いて、Marshal.SizeOf()とsizeof()が互換性があるかどうかを調べることが主なポイントでした。もしそうでなければ、なぜ誰かが他のものを使用するのでしょうか? – cogumel0

答えて

1

まず、知りたいのはなぜですか?あなたのコードがよく書かれている場合は、sizeofMarshal.SizeOfが返すものについて何も仮定する必要はありません。あなたのIntPtrインスタンスのいずれかをマーシャリングするためにマーシャラーを使用しますか?次に、Marshal.SizeOfを使用します。あなたの変数は管理された世界を離れることはありませんか、カスタムマーシャリングを使用していますか?その後、sizeof(またはunsafeブロックを必要としないので、IntPtr.Size)を使用します。いずれの場合でも、これらの値が同じ値を返すかどうかは関係ありません。それが実用的な答えです。

オン理論。 C# language specificationによれば、sizeof(IntPtr)に返される値は、 "IntPtrが構造体であるため、"すべてのパディングを含むその型の変数の合計バイト数 "です。しかし、この値は "実装定義"であることにも注意してください。だから、技術的なことを知りたければ、C#の仕様は単に "それを理解する"と言います。 IntPtrのドキュメントは、それがクリアタイプは、32ビットのIntPtrが対応ビルトインタイプの特殊であることを32ビットプラットフォームおよび64ビット、64ビット・プラットフォーム上の、そしてECMA-335文書上にあることになり、言っ

native intに変更されていますので、仕様に準拠している実装ではsizeof(IntPtr)が予測可能であると仮に判断できます.4ビットの32ビットプラットフォームでは8、64ビットプラットフォームでは8です。代わりにIntPtr.Sizeがあり、それは明示的に書かれています。

Marshal.SizeOf(typeof(IntPtr))は別の獣です。これは、「アンマネージタイプのサイズ」以外のものが返すものを正確には記述しません。水の下では、CLRのネイティブコードを呼び出して、TypeHelperにサイズの基礎となる型を問い合わせます。 IntPtrの場合、これは、C++コンパイラとプラットフォームの大半では、32ビットプラットフォームでは4で、64ビットプラットフォームでは8です(C++で)sizeof(void*)を返します。

理論的には、理論的には、sizeof(IntPtr)Marshal.SizeOf(typeof(IntPtr))は異なる可能性があります。しかし、ランタイムとジッタ(またはAOTコンパイラ)の組み合わせがsizeof(IntPtr)Marshal.SizeOf(typeof(IntPtr))にしないと賢明ではないので、これはあなたが一般的に心配するものではありません。そうでなければ、ランタイムはただ独自のものです人生はより困難です。一方、私が指摘したように、なぜあなたがに依頼する必要があるのか​​という理由はありません。も同じです。

1

一つには、プリミティブ型があります:

| x64 | x86
| Marshal. | Marshal.
Primitive | SizeOf<T>() sizeof(T) | SizeOf<T>() sizeof(T)
========= | =========== =========== | =========== ===========
Boolean | 4 <-> 1 | 4 <-> 1
Byte | 1 1 | 1 1
SByte | 1 1 | 1 1
Int16 | 2 2 | 2 2
UInt16 | 2 2 | 2 2
Int32 | 4 4 | 4 4
UInt32 | 4 4 | 4 4
Int64 | 8 8 | 8 8
UInt64 | 8 8 | 8 8
IntPtr | 8 8 <-> 4 4
UIntPtr | 8 8 <-> 4 4
Char | 1 <-> 2 | 1 <-> 2
Double | 8 8 | 8 8
Single | 4 4 | 4 4

さらに、のstruct(ValueType)インスタンスの場合、内部管理レイアウトとマーシャリングイメージの間には、合計サイズとフィールドレイアウトの順序の両方に大きな違いがあります。後者は、いわゆるformatted classesでも真です。 は、[1]

それは実際に実際の管理構造体のレイアウトに関する情報を必要とすることはまれだし、実際に.NETはそれを発見でき作ろうとして偉大な長さになります。また、構造体の内部レイアウトに影響を与えることもできません。その理由は、Marshalレイヤーがinteropに必要なレイアウトを明確に宣言する機能を提供する理由です。

構造体のランタイムメモリイメージの実際のサイズを知る必要があるユースケースです:ある種のストレージBLOBコンセプトに構造体の配列を使用していて、各チャンク(配列)を一定の総割り当てサイズ、たとえば〜84,800バイトの下に留まります。このケースでは明らかにLOHのままです。この記憶域クラスは、「レコード」またはテーブルエントリを定義する任意のValueTypeタイプでパラメータ化された汎用クラスにする必要があります。各管理対象配列チャンクに入ることができる構造体の数を判断するには、実行時に与えられた構造体の真のサイズを発見する必要があります。そのため、84,800をその値で割ります。管理・内部構造体のレイアウト、パディング、およびサイズ対をマーシャリングの間に発生する可能性の違いのより詳細な検査のため

は、「How do I check the number of bytes consumed by a structure?

に私の拡張の回答を参照してください。


[1。] "A フォーマット済みクラスは、レイアウトがStructLayoutAttribute属性で指定された参照タイプで、LayoutKind.ExplicitまたはLayoutKind.Sequentialのいずれかとなります。
https://msdn.microsoft.com/en-us/library/2zhzfk83(v=vs.110).aspx

関連する問題