「Struct」の意味や使い方 わかりやすく解説 Weblio辞書 (original) (raw)

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

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

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

オブジェクト指向言語でない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; }

近代的なAPI設計では、このようにしてC互換のオブジェクト指向インターフェイスを定義することがよくある。例えばOpenCL[10]Vulkan[11]などで類似の手法が実際に利用されている。ヘッダーでは構造体の前方宣言だけをすることにより、構造体の具体的な詳細(定義)はAPIのユーザーからは隠蔽されており、不透明な型 (opaque type) として扱われる(カプセル化)。

この手法を使うことで、C互換のインターフェイスを維持しつつ、API関数の実装をCだけでなくC++や他の言語で記述することもできるようになる。また、オブジェクトの生成・破棄を含むあらゆる操作をAPI関数経由に限定し、オブジェクトハンドルを介した操作のみを提供することで、異なるABI間でも正しくオブジェクトをやりとりすることができるため、C/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 { ///

カプセル化されたフィールド。 private int _x, _y; /// X座標を取得・設定するプロパティ。 public int X { get => _x; set => _x = value; } /// Y座標を取得・設定するプロパティ。 public int Y { get => _y; set => _y = value; } /// 原点からの距離を取得するプロパティ。 public double Distance => Math.Sqrt((double)_x * (double)_x + (double)_y * (double)_y); /// 引数付きコンストラクタ。 public MutablePoint(int x, int y) { _x = x; _y = y; } /// System.ValueTypeのToString()メソッドをオーバーライド。 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 APIなどで定義されている構造体と互換性のある型をC#の構造体によってユーザー定義することで、P/Invokeに利用できる。

VB.NETF#といった.NET言語も、構文は異なるがC#と同様の構造体を備えている[7][14]

C++/CLIでは、value structまたはvalue classによって.NETの構造体型を定義することができる[15]

アライメント

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

脚注

注釈

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

出典

  1. ^ User-defined data type (VBA) | Microsoft Docs
  2. ^ レコード・クラス | Oracle Java SE 16 Help Center
  3. ^ Java 16の最新情報 | InfoQ
  4. ^ データクラス - Kotlin Programming Language
  5. ^ a b 構造体型 - C# リファレンス | Microsoft Docs
  6. ^ a b クラス - C# プログラミング ガイド | Microsoft Docs
  7. ^ a b Structure ステートメント - Visual Basic | Microsoft Docs
  8. ^ 構造体とクラス(Structures and Classes) · The Swift Programming Language日本語版
  9. ^ Structures and Classes — The Swift Programming Language (Swift 5.6)
  10. ^ OpenCL-Headers/cl.h at master · KhronosGroup/OpenCL-Headers
  11. ^ Vulkan-Headers/vulkan_core.h at master · KhronosGroup/Vulkan-Headers
  12. ^ Choosing Between Class and Struct - Framework Design Guidelines | Microsoft Docs
  13. ^ Parameterless struct constructors - C# 10.0 draft specifications | Microsoft Learn
  14. ^ Structures - F# | Microsoft Docs
  15. ^ ref class and ref struct (C++/CLI and C++/CX) | Microsoft Docs
  16. ^ StructLayoutAttribute Class (System.Runtime.InteropServices) | Microsoft Docs
  17. ^ Storage and Alignment of Structures | Microsoft Docs

関連項目

データ型
ビット列 ビット トリット ニブル オクテット バイト ワード ダブルワード
数値 整数型 符号付整数型 十進型(英語版) 有理数型(英語版実数型 複素数型 固定小数点型 浮動小数点型 半精度 単精度 倍精度 四倍精度 八倍精度(英語版拡張倍精度 ミニフロート bfloat16 ブロック浮動小数点
ポインタ 物理アドレス型 論理アドレス型(英語版) 仮想アドレス型(英語版参照型
テキスト キャラクタ型 ストリング型 ヌル終端
複合 配列 可変長配列 連想配列 構造体 レコード 共用体 タグ共用体(英語版タプル コンテナ リスト キュー スタック セット ツリー 代数的データ型
その他 ブーリアン型 void型 null型 列挙型 再帰データ型 トップ型(英語版ボトム型 関数の型(英語版) 不透明型(英語版) シンボル型(英語版Nullable型 Option型 Result型
関連項目 データ構造 型システム プリミティブ型 抽象型 抽象データ型 ボックス化 動的束縛
カテゴリ