この記事は検証可能な参考文献や出典が全く示されていないか、不十分です。出典を追加して記事の信頼性向上にご協力ください。(このテンプレートの使い方)
出典検索?: "構造体"
この項目では、プログラミング言語について説明しています。工学分野については「構造工学」をご覧ください。
構造体(こうぞうたい、英: structure)はプログラミング言語におけるデータ型の一つで、1つもしくは複数の値をまとめて格納できる型。それぞれのメンバー(フィールド)に名前が付いている点、またメンバーの型が異なっていてもよい点が配列と異なる。レコードという名前の類似機能として実装されている言語もある。
C/C++やC#などでstructとしてサポートされているほか、Visual Basic/VBAのユーザー定義型Type[1]や、PascalやAdaのrecord型も構造体に相当する。
クラスベースのオブジェクト指向言語では、抽象データ型としてのクラスが構造体の役割をも内包する。Cの文法を継承した言語ではstructキーワードを含むこともあるが、言語によってその役割や性質は異なる。
C++のstructは、アクセシビリティの初期値がpublicであることを除いて、classと同等の機能を果たす。メンバー変数だけでなくメンバー関数を持つこともでき、派生型を定義することもできる。
Javaでは、structキーワードは存在しない。すべてのユーザー定義型は参照型であり、構造体に相当するデータ構造はclassキーワードを使ってクラスとして実現する必要がある。Java 16ではイミュータブルな「レコードクラス」をサポートする[2][3]。
Kotlinでは、データを保持するためだけのクラスとして、data class構文により「データクラス」を定義することができる[4]。データクラスはミュータブル[注釈 1]だが、通常のクラス同様に参照型であることには変わりなく、変数の代入は参照のみのコピーとなる。そのため、すべてのプロパティをコピーした新たなオブジェクトを生成するには、コンパイラの推論によって暗黙的に自動定義されたcopy()関数を使うなどする。サブクラスを定義することはできない。
C#では、構造体の定義にstructキーワードを使用する[5]。classキーワードにより定義されるクラス[6]は「参照型」である一方、構造体は軽量なオブジェクト型を定義するための「値型」であり、クラスと比較していくつかの制約がある。
VB.NETでは、構造体の定義にStructureキーワードを使用する[7]。姉妹言語であるC#の構造体と類似の機能である。
Swiftでは、構造体の定義にstructキーワードを使用する。C#と同様、classキーワードにより定義されるクラスは参照型である一方、構造体は値型である[8][9]。SwiftのクラスはObjective-Cのクラスに対応する概念であり相互運用できるが、構造体は相互運用することができない。
オブジェクト指向言語でないCなどでオブジェクト指向プログラミングを模倣するために構造体を使うこともある。
C言語の例.mw-parser-output .side-box{margin:4px 0;box-sizing:border-box;border:1px solid #aaa;font-size:88%;line-height:1.25em;background-color:#f9f9f9;display:flow-root}.mw-parser-output .side-box-abovebelow,.mw-parser-output .side-box-text{padding:0.25em 0.9em}.mw-parser-output .side-box-image{padding:2px 0 2px 0.9em;text-align:center}.mw-parser-output .side-box-imageright{padding:2px 0.9em 2px 0;text-align:center}@media(min-width:500px){.mw-parser-output .side-box-flex{display:flex;align-items:center}.mw-parser-output .side-box-text{flex:1}}@media(min-width:720px){.mw-parser-output .side-box{width:238px}.mw-parser-output .side-box-right{clear:right;float:right;margin-left:1em}.mw-parser-output .side-box-left{margin-right:1em}}ウィキブックスに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#における構造体は、小規模なデータ構造の定義に適した値型 (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()メソッドをオーバーライド。
C#の例