• ベストアンサー

c言語について教えて下さい

知り合いのコードを解析していたときのことです。 彼のコードにはマクロはあまり多くなく、構造体や列挙型を使用していました。 コードの書き方は人それぞれではありますが、マクロで一つずつ定数などを扱うよりも、一つのグループとして構造体や列挙型を使い扱ったほうがよいのでしょうか、教えてください。 また、話は変わるのですが、構造体と列挙型の違いを教えてください。調べたのですがいまいちわかりません(・・;) よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.2

マクロ(#defineプリプロセッサの事だよね?)による定数の置き換えと列挙体の違いは、 マクロはコンパイル前に置き換えが完了するのでC言語の外の話だが、 列挙体はC言語の言語仕様であり文法や値もコンパイルに影響する。 つまり、 ~~~~test.c~~~~ #include <stdio.h> #define HOGE 1 int main(int argc, char **argv) {  printf("%d\n", HOGE); } ~~~~~~~~ は、コンパイル時には ~~~~プリプロセス後のtest.c~~~~ ・・・・ここにstdio.hの中身がばーばー書かれてる・・・・ int main(int argc, char **argv) {  printf("%d\n", 1); } ~~~~~~~~ こうなっている。もはやソース中にHOGEの名前は無く、printfの引数も1というintのリテラルだ。列挙体の場合はコンパイル直前もコンパイルしても列挙体のままだ。なのでコンパイル後のオブジェクトとしても実行時にメモリにロードされる内容として列挙体として扱われる。 話は変わるのですが構造体と列挙体の話。 構造体はイメージ的には複数の変数を一塊にする機能だ。 struct hoge { int i; int j; char c; char d; char e; char f; } とすると、intが4バイトでcharが1バイトの場合はこの構造体を作ると12バイトのメモリが消費される。 列挙体というのはこれとは全く関係なく、イメージ的にはdefineプリプロセッサとほぼ同じ。システマチックな違いは前段で触れたとおりだ。 さて、構造体と列挙体はほとんど関連性の無い概念だとわかって貰えたと思うが、構造体と対比するのであれば列挙体ではなくて共用体であろう。共用体はあるメモリに対して複数長のアクセスを実現する機能だ。 struct fuga { int i; char c; } union manimani { int i; char c; } この構造体と共用体の違いは、fuga.iとfuga.cは別々の変数だが、manimani.i(の下位1バイト)とmanimani.cは同じ場所を指している。 ~~~~テストコード~~~~ struct fuga f; f.i = 65535; f.c = 20; printf("%d\n", f.i); union manimani m; m.i = 65535; m.c = 20; printf("%d\n", m.i); ~~~~~~~~ というのを実行してみればその違いが分かるだろう。

その他の回答 (2)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

まず、C言語か、C++言語か、はっきりさせてください。 次のサンプルプログラムを例にします。 #define M0 (0) #define M1 (1) struct S { static const int S0=0 ; static const int S1=1 ; }; enum A {A0=0, A1=1}; enum B {B0=0,B1=1}; void subA(enum A a ) { } int main(){ enum A a0 = A0 ; enum A a1 = M1 ; enum B b0 = A0 ; enum B b1 = B1 ; subA(A1); subA(a0); subA(a1); subA(B1); subA(b0); subA(b1); subA(M0); return 0 ; } マクロ、列挙型と同列に構造体がきていることから、この struct sA のような使い方が連想されます。 このような使い方は C言語では文法エラーとなり利用できません。 C++では、一連の定数を関連付けたり、namespaceの代用にしたり、といった目的で利用できます。 enumの利点は「型をチェックできる」ことでしょう。 enum B b0 = A0 ; subA(B0); subA(b0); これらは、数値だけを見れば同じことですが、コンパイル時に「型が違う」と警告が出ます。 ところが enum A a1 = M1 ; subA(M0); では何も出ません。これは ・マクロはコンパイル前に置換されて、数値を直書きしたのと同等に扱われる ・enumと整数との間に暗黙の型変換がある ということからです。 C++ではより厳格になり、警告ではなエラーになります。 また、整数との暗黙の型変換も無くなったので、 「subA(M0);」等もエラーになります。 定数としてのenumの欠点は「整数型しか使えない」ことです。 enum F { F0=0.5 } 等とはできません。 #define F0 0.5 は可能です。 定数としてのマクロの利点であり欠点でもあるのが「型が無い」ことです。 C++でsubF(double) と subF(int)があった場合 subF(F0) と記述したとき #define F0 0.0 と #define F0 0 とでは呼び出される関数が別になります。 doubleの方を使いたいのなら subF((double)F0) とか #define F0 (double)0 とか明示する、という方法があります。 他の方法として、マクロではなく const double を使うものがあります。 const double F0=0.0 ; なら、F0は常にdoubleです。=0 と書いても、暗黙の型変換がはたらきます。 これを関連する定数をまとめる方法の一つとして、「structのstaticメンバーにする」というのがあります。 その例が struct S です。 > 構造体と列挙型の違い これは、まったく別のものです。 構造体は、いわば複数の変数をひとまとめにして扱うためのもの 列挙型は、一連の「名前」を扱うためのものです。

tapara
質問者

お礼

なるほど!とてもわかり易い説明ありがとうございます!これで違いが分かりました!

  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.1

>コードの書き方は人それぞれではありますが、マクロで一つずつ定数などを扱うよりも、一つのグループとして構造体や列挙型を使い扱ったほうがよいのでしょうか、教えてください。 この文章で「構造体」が出てくるということは、構造体そのものがわかってないように思えますけど。 例えば列挙型は、 enum A { A1 = 1, A2 = 2, }; は、enumを使わずに #define A1 1 #define A2 2 と、することも可能ですが構造体はできませんよ。 struct A { int A1; int A2; }; 列挙型は、値に名前を付け、それをまとめて型としたもの。 構造体は、複数の変数をまとめて、それを型としたもの。 となるかと。

tapara
質問者

お礼

列挙型はマクロの代わりに使えるのですね! ありがとうございます!

関連するQ&A