コンテンツにスキップ

構造体

出典: フリー百科事典『ウィキペディア(Wikipedia)』

: structure1

C/C++C#structVisual Basic/VBAType[1]PascalAdarecord

Cstruct

C++structpublicclass

Javastructclass使Java 16[2][3]

Kotlindata class[4][ 1]copy()使

C#struct使[5]class[6]

VB.NETStructure使[7]C#

Swiftstruct使C#class[8][9]SwiftObjective-C

C使

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;
}

下記は構造体へのポインタをユーザー定義のオブジェクト型のハンドルとして利用する例である。

/* MyObject.h */
/* 構造体の前方宣言 */
typedef struct MyObject MyObject;

extern MyObject* MyObject_create(void); /* コンストラクタの代替 */
extern void MyObject_destroy(MyObject* obj); /* デストラクタの代替 */
extern void MyObject_setPosition(MyObject* obj, double x, double y);
extern void MyObject_getPosition(const MyObject* obj, double* outX, double* outY);
/* MyObject.c */
#include <stdlib.h>
#include <assert.h>
#include "MyObject.h"

/* 構造体の定義 */
struct MyObject {
    double x, y;
};

MyObject* MyObject_create(void) {
    return calloc(1, sizeof(MyObject));
}
void MyObject_destroy(MyObject* obj) {
    free(obj);
}
void MyObject_setPosition(MyObject* obj, double x, double y) {
    assert(obj);
    obj->x = x;
    obj->y = y;
}
void MyObject_getPosition(const MyObject* obj, double* outX, double* outY) {
    assert(obj && outX && outY);
    *outX = obj->x;
    *outY = obj->y;
}

APICOpenCL[10]Vulkan[11]API (opaque type) 

使CAPICC++APIABIC/C++

C#[]


C# (value type) [5]C# (reference type) [6]使[12]

 (bool, char, int, double, etc.) 
// int 型の数値リテラルも構造体 (System.Int32) のインスタンスであり、オブジェクトである。
string str = 123.ToString();

structキーワードを使用した、ユーザー定義の構造体の例を下に示す。プロパティやメソッド定義の一部にC# 6.0やC# 7.0で追加された糖衣構文が使用されているが、構造体自体はC# 1.0当初から存在する言語機能である。なお、C#の構造体は引数付きコンストラクタをユーザー定義することはできるが、引数のないコンストラクタ(デフォルトコンストラクタ)をユーザー定義することはできない。また、フィールドやプロパティを宣言時初期化することもできない。引数のないコンストラクタでは、各フィールドはその型の既定値で初期化される。C# 10.0以降の構造体は、引数のないコンストラクタをユーザー定義することもできるようになった[13]

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) が表示される。
        TranslatePoint(ref point, -2, 3);
        Console.WriteLine(point.ToString()); // (3, 14) が表示される。

        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;
    }
    static void TranslatePoint(ref MutablePoint p, int dx, int dy) {
        p.X += dx;
        p.Y += dy;
    }
}

C#

C#C/C++便Windows APIC#P/Invoke

VB.NETF#.NETC#[7][14]

C++/CLIvalue structvalue class.NET[15]

アライメント[編集]

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

脚注[編集]

注釈[編集]

  1. ^ データクラスのすべてのプロパティをvalで宣言することで、イミュータブルにすることもできる。

出典[編集]

関連項目[編集]