プロが教える店舗&オフィスのセキュリティ対策術

C言語初学者です
列挙型の変数が一体どんなものなのかよくわかりません

列挙型の変数を宣言して、その変数に代入するとき、

enum goo{
zero = 0,
one,
two
};

enum goo num = zero;

のような感じで書いてあるのですが、この変数の宣言を

int num = 0;

としても同じだし、また、列挙型の変数への代入は列挙型の定数(zero, one...)を使用せず、

enum goo num = 10;

と書いても、実際は

int num = 10;

と変わらないと考えてよいのでしょうか?
つまり結局、列挙型の変数はint型変数と変わりないということでしょうか?

質問者からの補足コメント

  • 例示のコードですが、参考本から抜き出してきたものです
    そんな使い方をされて本気で意味が分からなかった結果ここにたどり着いたので、粗悪より悪い言葉使ってもいいと思います
    enum number{
    zero,
    one,
    two
    };

    enum number n; //列挙型変数の宣言

    n = two;

    printf("%d\n",n);

    という風に使っていて、まったく意図がわかりませんでした
    それならintでいいじゃん...しかも使うのprintfではなく、True, Falseじゃない?と思いました

    そして回答から言うに、その本で書かれている「列挙型変数」とは、後付けで編集可能な列挙型のような立ち位置で、int変数などとの違いは、アドレスから引っ張り出して計算しているか、シンボルとして直接計算しているかで、表面的にあまり変わりはないと理解してよいでしょうか

      補足日時:2024/01/15 23:09
  • うれしい

    たくさんのご回答ありがとうございます
    もしかしたら自分は沼に片足突っ込んでいたのかもしれませんね...
    しかしまず、typedef enum num{} NUMBER; NUMBER a が int a と表面的には同じということを知ることができ、加えて列挙型の深堀した解説もお聞きできてよかったです

    自分は、まだC言語の学習を標準入出力と処理制御くらいまでしか進んでおらず、作ったトイプログラムと言えばうるう年と素数の判定くらいなので、今の段階では列挙型自体を使えればよいという認識で、学習を進めていきたいと思います

    改めましてご回答ありがとうございました!

      補足日時:2024/01/16 22:42

A 回答 (7件)

う〜む。


まぁ、極端な話、Cの「型」ってのは突き詰めると、あってないようなモノで、全部数値に落ち着いちゃうからそっちから考えると混乱するとは思うよ。
そうじゃなくって、「用法」から考えた方がベターなんじゃないのかな。つまり、ある局面に於いて、ある「機能」は、「便利だから」存在する、と言う考え方だ。
個人的にはCは得意じゃないんだけど、ちと説明してみようか。

プログラミングをやってると、何らかの「名前」だけを使いたい、って場合が多いんだ。
そういう「名前だけを」使えるプログラミング言語もあるんだけど、一般にそういうのは許されないケースの方が多い。
例えばオセロを考える。盤面の「状態」は、黒、白、空、盤外の4つ。直接に黒、白、空、盤外と言う「名前」を使ってプログラムを書きたいんだけど、そいつは許されないわけだよな。
通常そういう時は変数を用意して、

int black = 0;
int white = 1;
int empty = 2;
int outer = 3;

とか書いて対応するわけだが・・・要はこんなん書くのがメンドいんだよ(笑)。出来ればそのままblack、white、empty、outerと言う「名称」を使いたい。
そういう「名称だけ使いたい」時に使うのが列挙体なんだ。
そして、上の例の時、blackには0が入ってて、whiteには1が入ってて・・・とか言うのも「たまたま」だ。別にblackが3でwhileが0で・・・でも構わないわけでしょ?要は「数値は区別の為に使われてるんであって、数値そのものには大した意味がない」。言い換えると「その数にせなアカン」と言う理論的な根拠は全くないわけだ(そしてwhite + empty = outerって言う「計算が成り立つ」なんつーのもオセロ、と言うゲームでは意味がない)。
そういう「数値自体に特に意味がない」時、プログラムする側が、何らかのトリッキーな事を考えてないのなら、「blackに何の数を代入すべきだ・・・?」とか熟考するのは無駄でしょ(笑)。だって目的は「識別の為」だけであって、使われてる数値自体には特に意味がねぇんだから。
この辺の数値選び、はコンパイラやインタプリタに面倒見てほしい。余計な事は何も考えたくないからだ。つまり、「自動で名前に数値を振り分けてくれれば便利なのに」を体現したのが「列挙体」だ。
列挙体、ってのは変な日本語だけど、英語では元々Enumerated Typeと呼ぶ。enumerateってのは「数え上げる」って意味なの。あるいは「数値を振り分ける」とかそういうニュアンス。
んで、他の人は「整数に名前を付けるもの」とか書いてるけど、モダンなプログラミングの観点は逆で、「名前に整数を振り分ける」って考えた方が分かりやすいと思う。enumerateされてるのは「名前」であって、数値じゃないし、上にも書いてきたけど、ここで言う「数値」、つまり整数はidナンバー以上の意味はないんだ。
んで、繰り返すけど、個人的にはCは得意じゃないんだけど、「列挙体の使用方法」で言うと、恐らくユーザー定義型と組み合わせた例の方が多いんじゃない?多分。
例えば上のオセロのようなケースだと、列挙体定義時にtypedefと組み合わせて、

typedef enum piece {black, white, empty, outer} piece_t;

と記述して「piece_t型」っちゅう「新しい型」を定義する。typedefによりユーザー定義型を導入する事で、プログラムはより「意味」が「明確」になる。ここにあるblack、white、empty、outerと言う「名前」は、既に設定された「整数」から意味が乖離している。
でもそれでいい。高級言語の存在意義は「人間にとって意味が見出しやすい」であり、「意味のある名前を使える」ってのは何にも増して代えがたいんだ。「blackは0だったから・・・」って覚えておく必要はなく、ここでは既にblackはpiece_t型のblack以上の意味はない。また、もし「数値を重要視して数値だけでプログラムを書きたい」んなら、高級言語なんかは使わずにマシン語でプログラムを書けばいいだろう、って話になるだろうしね。
繰り返すけど、数値を使わず、「名前によって人にとっての意味を明確化する」ってのは高級言語の重要なコンセプトなんだ。
なお、typedefと列挙型の組み合わせは、例えば素の列挙体で、

enum eng {foo, bar, baz};
enum jap{hoge, fuga, piyo};

とした場合、foo == hogeなんつー判定が出来るトコを

typedef enum eng {foo, bar, baz} eng_t;
typedef enum jap{hoge, fuga, piyo} jap_t;

ではfoo == hogeの判定を許さない・・・いや、言い過ぎだな。コンパイルは通るかもしんないけど、Warningが出る処理系が多いだろう。「ユーザー定義型」として新しい型、eng_t型とjap_t型を設定した以上、fooに設定された0とhogeに設定された0は「意味が違う」事となる。これがバグを未然に防ぐ事にも繋がるだろう。
分かったかしらん?実態は突き詰めると整数型だろ、とか言うのは正しいんだけど、そうじゃなくって「プログラマが意味ある名前をそのまま使いたい」(そして設定された数値自体に意味はさしてない)場合に利用するのが列挙体の存在意義なんだ。

※1: ちなみに、挙げられたプログラム例の

enum number{
 zero,
 one,
 two
};

enum number n; //列挙型変数の宣言

ってのは多分冗長な定義法なんじゃないか・・・・・・Cの仕様上、

enum number{
 zero,
 one,
 two
} n; // n は列挙型変数の宣言

と記述すれば即刻nはenum number型の変数と認識される筈だ。

※2: 実の事を言うと、昨今のモダンなプログラミング言語だと、列挙体自体が存在しない言語の方が多いんじゃないか・・・列挙体が「ある」のはC言語系の例えばJava、あるいは既に古い言語になっちまったPascal、とかだけど、PythonやRubyなんかの言語だと存在しない(Rubyの列挙型ってのはここでの列挙体とは意味が違うし)。
だから、モダンな言語デザイナー達自身が、「あんま列挙体使わんかったな・・・」とか思ってる、って事かもしんない(笑)。使わんかったから自身の言語からその機能を削除した、とか(笑)。
そう考えると、あるいは今後別のプログラミング言語へ移動する、って事を視野に入れると、そんなに頑張って「列挙体を使いこなせるようにならなければ!」って程じゃないのかもしんない(笑)。
    • good
    • 1
この回答へのお礼

列挙型について疑問だったところとその周辺まで解説していただき、ありがとうございました!

お礼日時:2024/01/16 22:44

仕様のこまかいところはともかく、


C言語においては
・「列挙型」は整数に名前を付けるもの。マクロに近い
・「列挙型変数」は「整数型変数」と同じもの
(ここでの「整数」はintとは限らない)
と考えといていいと思う。


> そして回答から言うに(略)

混同しているようですが
その例題だと
zero,one 等は「enum number列挙型の値」であって「列挙型変数」ではありません。
列挙型変数と呼べるのは「enum number n;」で宣言した変数nです。



なお、C++では判定が厳しくなっており、
enum goo num = 10;
等はできなくなっています。
    • good
    • 1

enumはenumeratedの略だ。

    • good
    • 0

まずこの質問文の例は, ぶっちゃけ「enum の意義をないがしろにしている」といっていいような気がする. 最大限好意的に解釈しても「粗悪」. #1 の例が一般的じゃないかなぁ....



enum の存在意義としては
「ただの int の数値」に「意味のある名前」を付ける
ことにあると思う. 関数の
「ただの処理の流れ」に「意味のある名前」を付ける
機能と対比できるかもしれない.

なお「必ず int」というわけではなく, char や unsigned int になる可能性もある.

しかし「equal number」とか, いったい誰がいいだしたのだか....
    • good
    • 1

全く違いますね。


enum goo num = 10;の意味は num という文字列が 10という文字列と等価であると言うことです。コンパイラ(プリコンパイラか1パス)がnumという文字列を10に置き換える事になります。
int num = 10;はnumという関数エリアを確保してそこに10を代入します。

ソースリストを見たときに数の意味をわかりやすくするために意味を持った単語に置き換えるのが効用ですがC,C#等ではコメントで表示すれば済みますから却って解りにくくなりますね。

enum goo numではint変数にでもdouble変数にでもerror,warnigにならずに代入できます。

enumはequal numberの略ですね。
    • good
    • 1

enum 型は読み込み専用で、値の更新はできません


可読性の観点から存在するといってもいい

enum goo num = 10;

const num = 10;
かな
昔(30年)前は、K&RのCのガチガチの人は、enumつかわなかったな
そしてソースが見にくいし、関数のプロトタイプ宣言しないので
関数がint引数、int戻りに仮定されるので困ったことが多かった
    • good
    • 1

同じなんですが。


enumを使うことで数字に意味を持たせることができます。

例えば

enum week{
Mon = 0,
Tue,
Wed,
Thu,
Fri,
Sat,
Sun
};

のようにします。

そうすると、
if(day == 0){
printf("月曜日\n");
}
よりも

if(day == Mon){
printf("月曜日\n");
}
のほうがわかりやすくなります。

あなたが個人で作ったプログラムならenumを使わなくても結構です。
ただ、他人が読む可能性があるソースコードの場合、enumを使ったほうがわかりやすくなります。
10年前のソースコードを読んで、「この3ってなんだっけ?」となることがよくあります。
この様な数字をマジックナンバーと言います。
enumを使えばマジックナンバーを使わずに済みます。
    • good
    • 2

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A