struct
「struct」の意味・「struct」とは
「struct」は、プログラミング言語CやC++において、複数の異なる型のデータを一つのグループとしてまとめるための構造体を表すキーワードである。これにより、異なる型のデータを一つの単位として扱うことが可能となる。例えば、学生の情報を管理する際に「名前」「学籍番号」「成績」など、異なる型のデータを一つの「学生」という構造体で管理することができる。「struct」の発音・読み方
「struct」の発音は、IPA表記では /strʌkt/ となる。IPAのカタカナ読みでは「ストラクト」となり、日本人が発音するカタカナ英語では「ストラクト」と読む。この単語は発音によって意味や品詞が変わる単語ではない。「struct」の定義を英語で解説
A 'struct' in the C and C++ programming languages is a keyword that denotes a structure, a composite data type that groups together variables of different types. For instance, when managing student information, different types of data such as 'name', 'student number', and 'grades' can be managed as a single 'student' structure.「struct」の類語
「struct」の類語としては、他のプログラミング言語における同様の概念を表す「class」や「record」がある。これらも同様に、複数の異なる型のデータを一つの単位として扱うことが可能である。「struct」に関連する用語・表現
「struct」に関連する用語としては、「union」や「enum」がある。これらもCやC++におけるデータ型を表すキーワードである。また、「struct」を用いて定義された構造体は、「インスタンス」を生成することが可能である。「struct」の例文
1. English example (Japanese translation): "In C programming, a 'struct' is used to group together different types of data." (C言語のプログラミングでは、「struct」は異なる型のデータをまとめるために使用される。)2. English example (Japanese translation): "The 'struct' keyword allows us to create a student structure with 'name', 'student number', and 'grades' as its members." (「struct」キーワードを使うことで、「名前」、「学籍番号」、「成績」をメンバーとする学生の構造体を作成することができる。)
3. English example (Japanese translation): "A 'struct' can also contain functions, known as methods." (「struct」はメソッドと呼ばれる関数も含むことができる。)
4. English example (Japanese translation): "The 'struct' keyword is also used in other programming languages such as C++ and C#." (「struct」キーワードは、C++やC#などの他のプログラミング言語でも使用される。)
5. English example (Japanese translation): "A 'struct' can be used to create complex data structures." (「struct」は複雑なデータ構造を作成するために使用することができる。)
6. English example (Japanese translation): "A 'struct' can be used to create a data type that can hold different types of data." (「struct」は、異なる型のデータを保持できるデータ型を作成するために使用することができる。)
7. English example (Japanese translation): "A 'struct' can be used to create a new data type that can hold a group of data." (「struct」は、一組のデータを保持できる新しいデータ型を作成するために使用することができる。)
8. English example (Japanese translation): "A 'struct' can be used to create a data structure that can hold a collection of data of different types." (「struct」は、異なる型のデータの集合を保持できるデータ構造を作成するために使用することができる。)
9. English example (Japanese translation): "A 'struct' can be used to create a data structure that can hold a set of data." (「struct」は、一組のデータを保持できるデータ構造を作成するために使用することができる。)
10. English example (Japanese translation): "A 'struct' can be used to create a data structure that can hold a group of related data." (「struct」は、関連する一組のデータを保持できるデータ構造を作成するために使用することができる。)
構造体
(struct から転送)
出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2022/11/02 18:42 UTC 版)
![]() | この記事は検証可能な参考文献や出典が全く示されていないか、不十分です。2011年11月) ( |
構造体(こうぞうたい、英: 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言語の例
下記は単純な例示のため、バッファオーバーフローや整数オーバーフローなどは考慮していないことに注意されたい。
#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 {
/// <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 APIなどで定義されている構造体と互換性のある型をC#の構造体によってユーザー定義することで、P/Invokeに利用できる。
VB.NETやF#といった.NET言語も、構文は異なるがC#と同様の構造体を備えている[7][14]。
C++/CLIでは、value struct
またはvalue class
によって.NETの構造体型を定義することができる[15]。
アライメント
構造体のメンバーのメモリレイアウトは、必ずしも連続しているとは限らない。実行環境(プロセッサアーキテクチャ)に合わせてアクセス効率が最適になるよう、コンパイラによってバイト境界に応じた無名の詰め物(パディング)が挿入されることがある。このパディングはシリアライズや相互運用などで問題になることがあるため、フィールド属性やコンパイラ特有のディレクティブによってアライメントを明示的に調整できる言語や処理系も存在する[16][17]。ただし、アライメントされていないアドレスに構造体メンバーが配置された場合、メンバーアクセスがバスエラーを引き起こすケースもある。
脚注
注釈
- ^ データクラスのすべてのプロパティを
val
で宣言することで、イミュータブルにすることもできる。
出典
- ^ User-defined data type (VBA) | Microsoft Docs
- ^ レコード・クラス | Oracle Java SE 16 Help Center
- ^ Java 16の最新情報 | InfoQ
- ^ データクラス - Kotlin Programming Language
- ^ a b 構造体型 - C# リファレンス | Microsoft Docs
- ^ a b クラス - C# プログラミング ガイド | Microsoft Docs
- ^ a b Structure ステートメント - Visual Basic | Microsoft Docs
- ^ 構造体とクラス(Structures and Classes) · The Swift Programming Language日本語版
- ^ Structures and Classes — The Swift Programming Language (Swift 5.6)
- ^ OpenCL-Headers/cl.h at master · KhronosGroup/OpenCL-Headers
- ^ Vulkan-Headers/vulkan_core.h at master · KhronosGroup/Vulkan-Headers
- ^ Choosing Between Class and Struct - Framework Design Guidelines | Microsoft Docs
- ^ Parameterless struct constructors - C# 10.0 draft specifications | Microsoft Learn
- ^ Structures - F# | Microsoft Docs
- ^ ref class and ref struct (C++/CLI and C++/CX) | Microsoft Docs
- ^ StructLayoutAttribute Class (System.Runtime.InteropServices) | Microsoft Docs
- ^ Storage and Alignment of Structures | Microsoft Docs
関連項目
- structのページへのリンク