質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

3回答

3196閲覧

構造体のサイズについて

Ojawa

総合スコア13

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

1グッド

2クリップ

投稿2019/05/01 15:43

編集2019/05/02 06:23

質問

クラスまたは構造体の選択より、

"インスタンスのサイズは 16 バイト未満である。"

とあったので、構造体のサイズについて調べてみたのですが、プロパティ・メソッドがサイズに含まれないのはなぜなのでしょうか?

該当のソースコード

C#

1struct MyData 2{ 3 private int x; // 4byte 4 public int X // 4byte 5 { 6 get { return x; } 7 set { x = value; } 8 } 9 10 public void GetThree() // 8byte ポインタ? 11 { 12 Console.WriteLine(x); 13 Console.WriteLine(x); 14 Console.WriteLine(x); 15 } 16}

C#

1class MyApp 2{ 3 static void Main() 4 { 5 Console.WriteLine(Marshal.SizeOf(typeof(MyData))); // 4 6 } 7}

試したこと

コードを実行する前は、int x:4 + int X:4 + void GetThree():8 = 16 バイトと思っていたのですが
期待する結果とは異なり、Marshal.SizeOf() の結果は"4"と出力されました。

疑問点

  • メソッドは、64bit の場合ポインタのサイズで 8 バイトではないのでしょうか?
  • プロパティは、int x を包括?するための仕組みなのでサイズはないのでしょうか?
KSwordOfHaste👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

Marshal.SizeOf Method

The size returned is the size of the unmanaged type. The unmanaged and managed sizes of an object can differ.

アンマネージ構造体にはプロパティもメソッドもありません。
なので省かれます。

投稿2019/05/01 22:16

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ojawa

2019/05/02 06:24 編集

* マネージ構造体 * アンマネージ構造体 上記は、GC 内で展開されるか、GC 外で展開されるかの違いと Marshal.SizeOf() がアンマネージのサイズを返却することは理解しました。 しかし、私の定義した構造体はアンマネージ構造体である理由が調べてもわかりませんでした。 追加の質問となり申し訳ないのですが、 * int x; // アンマネージ領域 * プロパティ・メソッド // マネージ領域 上記で展開されるという意味で合っていますでしょうか。
Zuishin

2019/05/02 06:30

KSwordOfHaste さんのおっしゃる通りメソッドおよびプロパティは構造体内部に領域を持つのではなくコード領域にあります。そしてそれへの参照は定数としてコンパイルされます。 Marshal.SizeOf はアンマネージ構造体にマーシャリングされた場合、どのサイズになるのかという数値を計算して返します。つまりこの時点では計算上の架空のサイズです。 マネージ構造体のサイズを取得するには、Marshal.SizeOf メソッドではなく、sizeof 演算子を使ってください。ただし、unsafe コンテキストが必要であるなど、いくつかの制限があります。 また 16 バイトというのは目安でしかなく、それ以上の構造体を作ることも可能です。ただし構造体は値型なので変数への代入やメソッドへの引き渡しにコピーが発生するため、大きいものはパフォーマンスが落ちる傾向があります。 16 バイトにはそれほどこだわらず、基本的に class を使い、特に構造体の方が良いパフォーマンスを得られると確信した場合にのみ構造体を使うのが良いでしょう。
guest

0

ベストアンサー

ご質問の例でいえばインスタンス上に必要な情報は

private int x;

これだけです。

プロパティ・メソッドがサイズに含まれないのはなぜなのでしょうか?

大抵のコンパイラー/インタープリタ言語でも同様なのですが、メソッドの類はインスタンス自身の内側に領域を持ってはいません。structだけでなくclassのインスタンスもそうです。

理由はどの実体であってもメソッドの実体(プロセッサーの機械語ないしは仮想マシンのIL/bytecodeの並び)は必ず同一になるからです。個々のインスタンスに依存しない同一の情報を各々のインスタンスの領域にわざわざ記録するのはメモリー領域の無駄使いでしかなく不合理です。

メンバー関数やプロパティーについて以下のコードをごらんください。

C#

1using System; 2 3public struct S { 4 public int x; 5 public void m1() { Console.WriteLine("m1: " + x); } 6 public int X 7 { 8 get { return x; } 9 set { x = value; } 10 } 11} 12 13public static class SImpl { 14 public static void m2(ref S self) { Console.WriteLine("m2: " + self.x); } 15 public static int getX(ref S self) { return self.x; } 16 public static void setX(ref S self, int value) { self.x = value; } 17} 18 19class App { 20 public static void Main() { 21 S s = new S() { x = 111 }; 22 s.m1(); 23 SImpl.m2(ref s); 24 25 s.X = 123; 26 Console.WriteLine("s.X = " + s.X); 27 28 SImpl.setX(ref s, 456); 29 Console.WriteLine("s.getX = " + SImpl.getX(ref s)); 30 } 31}

この構造体はm1というメソッド、Xというプロパティーを持ってますが、SImplにあるm2, getX, setXを用いるとm1やXを使用するのとまったく同じことができていることがおわかりでしょか?
実はコンパイラーはm1やXをちょうどこんな雰囲気に展開してくれているのです。

そのためSの領域自体の中にはxというフィールドしか必要なく、当然ながらSizeOfも4を返すというわけです。

ソフトウェアはどんなものであれ「合理的」に設計されています。プログラムの実行効率(メモリー量やスピード)に大きな影響を及ぼす言語処理ソフトウェア(コンパイラーやランタイム)では特に効率に関する合理性の追求が顕著であり、常に可能な限り最高の効率を目指して設計されているのが普通です。

アプリケーションを書く上では仕様書を参照し「どういう仕様であるか」を知っていさえすれば充分と言えますが、もう少し突っ込んで低水準な言語処理系の本質に関して学ぶと仕様の根拠が見えてくることがあります。自分はC++に初めて触れたときC++がvirtualなメンバー関数をどのようにして実現しているかコンパイルされたコードを観察して「うーむ、なるほどうまいこと考えるものだ」と感心したことを覚えています。こういうことを少し学んでおくと「なぜこういう仕様になっているか」「何に気を付けなければならないか」がより深く把握できる気がします。

そういう意味で質問者さんが「実際にサイズがどうなるか」を調べたり「それが何故か」を考えておられるのは価値あることだと思いました。

投稿2019/05/02 03:58

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ojawa

2019/05/02 06:23 編集

詳しい解説ありがとうございます。 * 構造体の領域には、int x のフィールドがある。 * プロパティ・メソッドはコンパイル時に別の領域に展開される。 * プロパティ・メソッドには、構造体の型情報よりアクセスしている。 上記のことから、構造体のサイズを取得する場合、構造体の領域内にある int x:4 バイトが返却されるイメージで合っていますでしょうか。
Ojawa

2019/05/02 05:57 編集

> そういう意味で質問者さんが「実際にサイズがどうなるか」を調べたり「それが何故か」を考えておられるのは価値あることだと思いました。 ありがとうございます。まだまだ勉強することがたくさんあるので、これからも頑張ります。
KSwordOfHaste

2019/05/02 05:57

> 合っていますでしょうか。 あってます。
Ojawa

2019/05/02 06:10

"インスタンスのサイズは 16 バイト未満である。"の条件としては、 * 構造体のメンバメソッド・プロパティは制限なし。 * 構想体のメンバフィールドは、16 バイト未満であること。 ということなのですね。 ありがとうございます、わかりやすい解説を頂きすーっと理解することが出来ました。
guest

0

クラスと構造体の使い分けで解説されていますが

パフォーマンスを理由に「クラスか構造体か」を選択するのなら
16バイトが閾値となる。(ので参考にしてね)

くらいの意味で、マイクロソフト自身も守っていないガイドラインなので
あまり深く考える必要はないと思います。

投稿2019/05/02 06:33

asm

総合スコア15147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問