構造体

出典: フリー百科事典『ウィキペディア(Wikipedia)』
ナビゲーションに移動 検索に移動

構造体(こうぞうたい、: structure)はプログラミング言語におけるデータ型の一つで、1つもしくは複数の値をまとめて格納できる型。それぞれのメンバー(フィールド)は型が異なっていてもよい点が配列と異なる。

C/C++C#などでstructとしてサポートされているほか、Visual Basicのユーザー定義型や、PascalAdarecord型も構造体に相当する。

クラスベースオブジェクト指向言語では、抽象データ型としてのクラスが構造体の役割をも内包する。Cの文法を継承した言語ではstructキーワードを含むこともあるが、言語によってその役割は異なる。

  • C++structは、アクセシビリティの初期値がpublicであることを除いて、classと同等の機能を果たす。
  • Javaでは、structキーワードは存在しない。すべてのユーザー定義型は参照型であり、構造体に相当するデータ構造はclassキーワードを使ってクラスとして実現する必要がある。
  • C#では値型として扱われる軽量なオブジェクト型を定義するためにstructキーワードを使用する。構造体は派生型を定義できないなど、制限されたclassとして振る舞う。

オブジェクト指向言語でないCなどでオブジェクト指向プログラミングを模倣するために構造体を使うこともある。標準ライブラリのFILE型がその典型的な例である。

C言語の例[編集]

#include <stdio.h>

/* PersonalDataを構造体として定義 */
struct PersonalData
{
  /* メンバー変数 (つまり構造体の要素) を名前と年齢とする */
  char Name[100];
  int Age;
};

/* 上で定義された構造体を使ってみる */
int main(void)
{
  struct PersonalData pd; /* 構造体変数の宣言 */
  struct PersonalData *ppd; /* 構造体へのポインタ */

  scanf("%s", pd.Name); /* 値を入力 */
  scanf("%d", &(pd.Age)); /* 値を入力 */

  ppd = &pd;
  ppd->Age++; /* ポインタの参照先のメンバーにアクセスするにはアロー演算子->を使う。*/

  printf("%s-%d\n", pd.Name, pd.Age);
  return 0;
}

C#の例[編集]

C#における構造体は、軽量のオブジェクトを表す値型である[1]

組み込みの軽量な型 (bool, char, int, double, etc.) もまた構造体である。

// 数値リテラルも構造体であり、オブジェクトである。
string str = 123.ToString();

structキーワードを使用した、ユーザー定義の構造体の例を下に示す。C# 6.0以上を想定している。

using System;

public struct MutablePoint {
    /// <summary>カプセル化されたフィールド。</summary>
    private int _x, _y;
    /// <summary>X座標を取得・設定するプロパティ。</summary>
    public int X {
        get => _x;
        set => _x = value;
    }
    /// <summary>Y座標を取得・設定するプロパティ。</summary>
    public int Y {
        get => _y;
        set => _y = value;
    }
    /// <summary>原点からの距離を取得するプロパティ。</summary>
    public double Distance => Math.Sqrt((double)_x * (double)_x + (double)_y * (double)_y);
    /// <summary>引数付きコンストラクタ。</summary>
    public MutablePoint(int x, int y) {
        _x = x;
        _y = y;
    }
    /// <summary>System.ValueTypeのToString()メソッドをオーバーライド。</summary>
    public override string ToString() => $"({_x}, {_y})";
}

class Test {
    // フィールドで定義された構造体内の全てのフィールドはデフォルト値0で初期化されている。
    static MutablePoint s_point;
    static void Main() {
        Console.WriteLine(s_point.ToString()); // (0, 0) が表示される。
        // デフォルトコンストラクタ呼び出し。
        var zeroPoint = new MutablePoint();
        Console.WriteLine(zeroPoint.ToString()); // (0, 0) が表示される。
        // 引数付きコンストラクタ呼び出し。
        var point = new MutablePoint(5, 11);
        Console.WriteLine(TranslatePoint(point, 1, -9).ToString()); // (6, 2) が表示される。
        Console.WriteLine(point.ToString()); // (5, 11) が表示される。

        Console.WriteLine("Press any...");
        Console.ReadKey(true);
    }

    // 構造体型 (値型) は、仮引数に値のコピーが渡されるため、
    // メソッド内での仮引数の操作によって呼び出し元の実引数の値が変更されることはない。
    // 引数がrefパラメータならば、
    // あるいはMutablePoint型がstructではなくclassで宣言されていたならば、
    // 仮引数の状態の変更は実引数の状態に影響する。
    static MutablePoint TranslatePoint(MutablePoint p, int dx, int dy) {
        p.X += dx;
        p.Y += dy;
        return p;
    }
}

C#のデータ型も参照のこと。

C#の構造体は属性によってメモリレイアウトを明示的に指定することができるため、C/C++の構造体との相互運用に便利である。

アライメント[編集]

構造体のメンバーのメモリレイアウトは、必ずしも連続しているとは限らない。実行環境に合わせてアクセス効率が最適になるよう、コンパイラによってバイト境界に応じた無名の詰め物(パディング)が挿入されることがある。このパディングはシリアライズや相互運用などで問題になることがあるため、フィールド属性やコンパイラ特有のディレクティブによってアライメントを明示的に調整できる言語や処理系も存在する[2] [3]

脚注[編集]

[ヘルプ]

関連項目[編集]