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

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

ただいまの
回答率

89.23%

構造体のサイズについて

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 1,953

Ojawa

score 13

質問

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

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

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

該当のソースコード

struct MyData
{
    private int x; // 4byte
    public int X   // 4byte
    { 
        get { return x; }
        set { x = value; }
    }

    public void GetThree()  // 8byte ポインタ?
    {
        Console.WriteLine(x);
        Console.WriteLine(x);
        Console.WriteLine(x);
    }
}
class MyApp
{
    static void Main()
    {
        Console.WriteLine(Marshal.SizeOf(typeof(MyData))); // 4
    }
}

試したこと

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

疑問点

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+6

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/02 15:05 編集

    * マネージ構造体
    * アンマネージ構造体

    上記は、GC 内で展開されるか、GC 外で展開されるかの違いと Marshal.SizeOf() がアンマネージのサイズを返却することは理解しました。
    しかし、私の定義した構造体はアンマネージ構造体である理由が調べてもわかりませんでした。

    追加の質問となり申し訳ないのですが、

    * int x; // アンマネージ領域
    * プロパティ・メソッド // マネージ領域

    上記で展開されるという意味で合っていますでしょうか。

    キャンセル

  • 2019/05/02 15:30

    KSwordOfHaste さんのおっしゃる通りメソッドおよびプロパティは構造体内部に領域を持つのではなくコード領域にあります。そしてそれへの参照は定数としてコンパイルされます。

    Marshal.SizeOf はアンマネージ構造体にマーシャリングされた場合、どのサイズになるのかという数値を計算して返します。つまりこの時点では計算上の架空のサイズです。

    マネージ構造体のサイズを取得するには、Marshal.SizeOf メソッドではなく、sizeof 演算子を使ってください。ただし、unsafe コンテキストが必要であるなど、いくつかの制限があります。

    また 16 バイトというのは目安でしかなく、それ以上の構造体を作ることも可能です。ただし構造体は値型なので変数への代入やメソッドへの引き渡しにコピーが発生するため、大きいものはパフォーマンスが落ちる傾向があります。

    16 バイトにはそれほどこだわらず、基本的に class を使い、特に構造体の方が良いパフォーマンスを得られると確信した場合にのみ構造体を使うのが良いでしょう。

    キャンセル

checkベストアンサー

+5

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

private int x;

これだけです。

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

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

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

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

using System;

public struct S {
  public int x;
  public void m1() { Console.WriteLine("m1: " + x); }
  public int X
    {
      get { return x; }
      set { x = value; }
    }
}

public static class SImpl {
  public static void m2(ref S self) { Console.WriteLine("m2: " + self.x); }
  public static int getX(ref S self) { return self.x; }
  public static void setX(ref S self, int value) { self.x = value; }
}

class App {
  public static void Main() {
    S s = new S() { x = 111 };
    s.m1();
    SImpl.m2(ref s);

    s.X = 123;
    Console.WriteLine("s.X = " + s.X);

    SImpl.setX(ref s, 456);
    Console.WriteLine("s.getX = " + SImpl.getX(ref s));
  }
}


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

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/02 14:53 編集

    詳しい解説ありがとうございます。

    * 構造体の領域には、int x のフィールドがある。
    * プロパティ・メソッドはコンパイル時に別の領域に展開される。
    * プロパティ・メソッドには、構造体の型情報よりアクセスしている。

    上記のことから、構造体のサイズを取得する場合、構造体の領域内にある int x:4 バイトが返却されるイメージで合っていますでしょうか。

    キャンセル

  • 2019/05/02 14:56 編集

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

    キャンセル

  • 2019/05/02 14:57

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

    キャンセル

  • 2019/05/02 15:10

    "インスタンスのサイズは 16 バイト未満である。"の条件としては、

    * 構造体のメンバメソッド・プロパティは制限なし。
    * 構想体のメンバフィールドは、16 バイト未満であること。

    ということなのですね。
    ありがとうございます、わかりやすい解説を頂きすーっと理解することが出来ました。

    キャンセル

+3

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 89.23%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる