「C言語/データ型と変数の高度な話題」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
M Fix
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
タグ: 2017年版ソースエディター
459 行
 
=== enum ===
列挙体( enumeration )は、名前の付いた整数の定数値の集合で構成されています。それぞれの列挙は、異なる列挙型( enumerated type )を構成します<ref name="jtc1-sc22-wg14-n1570-6.2.5">{{cite book
列挙体とは、識別子をもった整数定数のリストである。
| url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
列挙体を用いることで、整数定数の代わりに識別子を使うことができ、
| title = N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x
ソースコードの可読性を高める。
| page=35, §6.2.5 ''Types''
| publisher = ISO/IEC}}</ref>。
<!-- N1256 p.35 §6.2.5 Types -- An enumeration comprises a set of named integer constant values. Each distinct enumeration constitutes a different enumerated type.-->
2つの列挙体の対応するメンバーは、同じ値を持たなければならない<ref name="jtc1-sc22-wg14-n1570-6.2.5">{{cite book
| url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
| title = N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x
| page=40, §6.2.7 ''Compatible type and composite type''
| publisher = ISO/IEC}}</ref>。
<!-- N1256 p.40 §6.2.7 Compatible type and composite type -- For two enumerations, corresponding members shall have the same values. -->
 
ISO/IEC 9899:2011(通称 C11)の §6.7.2.2 ''Enumeration specifiers''(列挙型指定子)を抄訳/引用します<ref name="jtc1-sc22-wg14-n1570-6.7.2.2">{{cite book
<syntaxhighlight lang="C">
| url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
//例 列挙体の使用例
| title = N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x
# include <stdio.h>
| page=105, §6.7.2.2 ''Enumeration specifiers''
| publisher = ISO/IEC}}</ref>。
 
<blockquote class="toccolours" cite="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf">
enum eNumber
;構文
{
:; ''{{Anchor|enum-specifier}}''
ZERO,
:: '''enum''' [[#identifier|identifier]]<sub>opt</sub> { ''[[#enumerator-list|enumerator-list]]'' }
ONE,
:: '''enum''' [[#identifier|identifier]]<sub>opt</sub> { ''[[#enumerator-list|enumerator-list]]'' , }
TWO,
:: '''enum''' ''[[#identifier|identifier]]''
};
:; ''{{Anchor|enumerator-list}}''
:: ''[[#enumerator|enumerator]]''
:: ''[[#enumerator-list|enumerator-list]]'' , ''[[#enumerator|enumerator]]''
:; ''{{Anchor|enumerator}}''
:: ''[[#enumeration-constant|enumeration-constant]]''
:: ''[[#enumeration-constant|enumeration-constant]]'' = ''[[#constant-expression|constant-expression]]''
:; ''{{Anchor|enumeration-constant}}''<ref>§6.4.4.3 Enumeration constants</ref>
:: ''[[#identifier|identifier]]''
; 制約条件
: 列挙定数の値を定義する式は、intとして表現可能な値を持つ整数定数式でなければならない。
; セマンティクス
: 列挙子リスト( ''[[#enumerator-list|enumerator-list]]'' )の識別子( ''[[#identifier|identifier]]'' )は、int型の定数として宣言されており、許容される範囲内であればどこにでも現れることができます。
: =を伴った持つ列挙子( ''[[#enumerator|enumerator]]'' )は、その列挙定数( ''[[#enumeration-constant|enumeration-constant]]'' )を定数式( ''[[#constant-expression|constant-expression]]'' )の値として定義します。
: 最初の列挙子に=がない場合、その列挙定数の値は 0 です。
: =がない後続の各列挙子は、前の列挙定数の値に1を加えた定数式の値としてその列挙定数を定義します。
: (=付きの列挙子を使用すると、同じ列挙内の他の値と重複する値を持つ列挙定数が生成されることがあります)。
: 列挙体の列挙子は、そのメンバーとしても知られています。
<!--
; Constraints
: The expression that defines the value of an enumeration constant shall be an integer constant expression that has a value representable as an int.
; Semantics
: The identifiers in an enumerator list are declared as constants that have type int and may appear wherever such are permitted.
: An enumerator with = defines its enumeration constant as the value of the constant expression.
: If the first enumerator has no =, the value of its enumeration constant is 0.
: Each subsequent enumerator with no = defines its enumeration constant as the value of the constant expression obtained by adding 1 to the value of the previous enumeration constant.
: (The use of enumerators with = may produce enumeration constants with values that duplicate other values in the same enumeration.)
: The enumerators of an enumeration are also known as its members.
-->
</blockquote>
構文中で、列挙子リスト( ''[[#enumerator-list|enumerator-list]]'' )の後ろに , がないケースとあるケースの両方が書かれているので、どちらの書き方も許されます。
 
;[https://paiza.io/projects/NXbg0pOVCrpf_eTHvTQq6w?language=cpp 列挙体の使用例]:<syntaxhighlight lang="C" highlight=18 line>
int main(void)
#include <stdio.h>
{
enum eNumber n;
n = ZERO;
printf("nの値は、%d。\n", n);
n=ONE;
printf("nの値は、%d。\n", n);
n = TWO;
printf("nの値は、%d。\n", n);
}
</syntaxhighlight>
上の例では、ソースコード中で0, 1, 2の代わりにZERO, ONE, TWOを用いることができる。
 
enum Day_of_the_Week {
列挙体の型枠の宣言の記述は次のようになっている。<ref>列挙体の型枠という用語はこの教科書独自のものであり、『JISX3010:2003』に出てくるわけではないので注意してください。</ref>
dwSUNDAY,
 
dwMONDAY,
<syntaxhighlight lang="C">
dwTUESDAY,
enum タグ名
dwWEDNESDAY,
{
dwTHURSDAY,
列挙定数 = 定数式,
dwFRIDAY,
:
dwSATURDAY,
:
nDay_of_the_Week,
};
</syntaxhighlight>
 
int main(void) {
「タグ名」で、列挙体の型枠に名前を付ける。
const char *names[nDay_of_the_Week] = {
列挙体のメンバ(要素のこと)を列挙定数と呼ぶ。
"日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日",
使用する列挙定数の数だけ、「列挙定数=定数式,」を含める。
};
 
for (enum Day_of_the_Week dw = dwSUNDAY; dw < nDay_of_the_Week; dw++) {
「列挙定数」で、その列挙定数の識別子を定める。
printf("%i: %s\n", dw, names[dw]);
「定数式」はint型で表現可能な値をもつ整数定数式でなければならない。
}
「列挙定数」は、型intをもつ定数として宣言され、
}
この型の定数が許されるところならばどこに現れてもよい。
 
「=定数式」でその定数式をもつ列挙定数を定義する。
「=定数式」は書かなくてもよい。
最初の列挙定数に「=定数式」がない場合、その列挙定数の値は0とする。
=がない2番目以降の各列挙定数は、
直前の列挙定数の値に1を加えた値とする。
 
列挙体の宣言の記述は次のようになっている。
 
<syntaxhighlight lang="C">
enum タグ名 変数名のリスト;
</syntaxhighlight>
 
列挙子の名前が <code>dw</code> で始まるのはタグ <code>'''D'''ay_of_the_'''W'''eek</code> の列挙子であることを示し、最後の列挙し <code>nDay_of_the_Week</code> 列挙子の総数で Number of <code>Day_of_the_Week</code> のつもり。列挙型の変数、<code>dw</code> はもちろん <code>enum '''D'''ay_of_the_'''W'''eek</code> 型であることを示しています。
タグ名で、列挙体の型枠を指定する。
変数名のリストで列挙体に名前を付ける。
複数の列挙体を宣言するときは、変数名を「,(コンマ)」で区切る。
 
この命名ルールは一例ですが、実際のプログラミングでは多くの識別子の名前を考える必要があるので、一貫性のある命名ルールを作ってコードを書くことで可読性・保守性が向上します。
なお、列挙体の型枠の宣言と列挙体の宣言とを、同時に行うこともできる。
次のように記述する。
 
[[C++]]のコードとしてコンパイルすると、dw++ がエラーになります<ref>[https://paiza.io/projects/idW8CifxFGXZ5bG1sdRdWA?language=c static_cast を使えば]、<syntaxhighlight lang="cpp" inline>dw = static_cast<Day_of_the_Week>(dw + 1)</syntaxhighlight>コンパイルできますが、<code>static_cast</code>は、コンパイラーの型チェックを骨抜きにしてしまうので、乱用は避けましょう(operator ++ をオーバーロードするにしても、その中で static_cast が必要)。</ref>。
<syntaxhighlight lang="C">
enum ===タグ===
ISO/IEC 9899:2011(通称 C11)の §6.7.2.3 ''Tags''(タグ)を抄訳/引用します<ref name="jtc1-sc22-wg14-n1570-6.7.2.3">{{cite book
{
| url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
列挙定数 = 定数式,
| title = N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x
:
| page=105, §6.7.2.3 ''Tags''
:
| publisher = ISO/IEC}}</ref>。
} 変数名のリスト;
</syntaxhighlight>
 
この場合、タグ名は省略することができる。
 
列挙体を使用するときの記述は次のようになっている。
 
<syntaxhighlight lang="C">
列挙定数
</syntaxhighlight>
 
<blockquote class="toccolours" cite="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf">
列挙定数の値は、列挙体の型枠の宣言で列挙定数に指定した定数となる。
; 制約事項
: 特定の型は、その内容が最大で一度だけ定義されなければならない。
: 以下の形式の型指定子は
:: '''enum''' ''[[#identifier|identifier]]''
: それが指定する型が完成した後にのみ現れるものとする。
; セマンティクス
: 同じスコープで同じタグを使用する '''struct'''、'''union'''、または '''enum''' の宣言はすべて同じスコープを持ち、同じタグを使用する '''struct'''、'''union'''、 '''enum''' のすべての宣言は、同じ型を宣言する。
: 型は、内容を定義するリストの閉じ括弧までは不完全で、それ以降は完全な型となります。
: '''struct'''、'''union'''、 '''enum''' の宣言のうち、スコープが異なるものや、異なるタグを使用しているものが2つあると、異なる型を宣言することになります。
: 異なるスコープまたは異なるタグを使用する2つの '''struct'''、'''union'''、 '''enum''' の宣言は、異なる型を宣言します。
: '''struct'''、'''union'''、または '''enum''' の各宣言でタグを含まない '''struct'''、'''union'''、 '''enum''' の宣言は、それぞれ個別の型を宣言します。
: 次のような形式の型指定子
:: struct-or-union identifieropt { struct-declaration-list }。
:: ''[[#struct-or-union|struct-or-union]]'' [[#identifier|identifier]]<sub>opt</sub> { ''[[#member-declaration-list|member-declaration-list]]'' }
:または
:: enum identifier { enumerator-list }
: の形式の型指定子。または
::enum identifier { enumerator-list , }
: は、 '''struct'''、'''union'''、または '''enum''' を宣言します。
: リストは、'''struct''' のコンテンツ、'''union''' のコンテンツ、または '''enum''' のコンテンツを定義します。
: 識別子が提供されている場合、型指定子は識別子をその型のタグであるとも宣言する。
</blockquote>
 
== 型修飾子 ==