• ベストアンサー

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% (1621/5656)
回答No.1

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

tapara
質問者

お礼

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

関連するQ&A

  • C言語ソースコードの解析

    私は現在組み込みのプロジェクトに参加おります、新米プログラマです。 既存の処理を理解したうえで設計しなければならないのですが、 元のソースコードに対して設計書が1つもなく、 ソース、ヘッダともにコメントなし、と言う状況です。 動作環境が無いので、ソースコードを解析して動作を理解しようとしています。 しかし、やっていることが複雑でなかなか進みません。 ■ポインタ/関数ポインタの嵐で、ポインタの実体を追っていくと、  30~40階層ほど上まで見なければならない。  (関数コールに、コールバックに、メッセージのやり取り)  関数ポインタを32bit整数の変数にキャストして代入し、  整数から関数ポインタに直したりしている。 ■構造体のメンバに他の構造体へのポインタがあり、  さらにその構造体は他の構造体のポインタを持っていて、  そのポインタが他の構造体の・・ などなど。 こういう複雑な他人のコードをどういう風に解析していますでしょうか? ご教授願います。

  • C言語、初心者が書けそうなプログラムとは?

     はじめにお断りしますが、私はプログラマーになるつもりは全くないです。  それとプログラムの知識もほとんど全くありません。  純粋に興味として質問をさせていただきます。 以下はC言語の入門者用の目次からなのですが、 ---------------------------- if,switch,for,while 2次元配列、自作関数、ポインタ、 関数への・コマンドプロンプトでの引数の渡し方 ファイルへの読み込み・書き出し バイナリファイルの入出力 構造体、共用体と列挙体、マクロ、 複数ファイルのプログラム malloc関数 ---------------------------- (1)以上のもの+α程度を習得して、さらに人の助言などによって発展性をもたらすことができたら、具体的に(※)何のプログラムが自作できますか? (※)カレンダー、オセロゲーム など?? (2)C言語を扱うプログラマーとして会社に入社して、最初の1年目で任せられるようなプログラムとは具体的にどういうものがありますか?  特に(2)の質問は範囲が広すぎて回答が困難だと予想されますが、質問している私自身が何もわからない人間なので、質問の範囲を狭めることができません。申し訳ありませんが上手く答えられる方、お願いします。

  • ANSYS 確率設計 要素ごとに材料定数をばらつ…

    ANSYS 確率設計 要素ごとに材料定数をばらつかせることは可能でしょうか? ANSYS 確率設計で構造解析をしています。 要素ごとに材料定数をバラつかせて、シンプルな板の座屈解析を考えて います。構造体そのものの材料定数をばらつかせることは出来るようですが、 要素ごとに材料定数をばらつかせることは出来るのでしょうか? ちなみに要素数は1000です。 簡単なコマンド等があれば助かるのですが・・・。

    • 締切済み
    • CAE
  • C言語のソースをC++言語に変換したい

    C言語で書かれていたソースをC++言語に変換したいのですが どのような点に気をつければよいでしょうか 現在、プログラムの主な構造は構造体とそれを扱う関数が実装されていて、 これらをクラスを使用して書き換えようと思います。 それ以外に気にしておくものはありますか。 例えば、ヘッダファイルで<stdio.h>をインクルードしているところがありますが、 これは<cstdio>に書き換えたほうがよいかもしれない、と言われたことはあります。 printfなどはprintfのまま使用しても大丈夫ですか。 std::printfに書き換えたり、iostreamを使用する方法に書き換えたほうがいいですか。 規格としてはどのようになっているのでしょうか。 (「過去との互換性のためにあるだけであり、非推奨」とかあったりしますか。)

  • c言語についてです。

    以下の条件で課題が出ました。 どなたか詳しい方いらっしゃいましたら回答お願いします。 1.main関数のほかに最低3つの関数を用いる。 2.構造体を使用すること 3.ステップ数は最低50ステップ以上 4.少なくとも1度はポインタを使用する処理を盛り込むこと プログラム動作内容を説明するドキュメントをつくる ソースファイルおよびコンパイル後の実行可能なファイルをつくる

  • C言語に関することについて教えてください

    学校の問題集にでてきた問題がわかりません、どうか教えてください 1 プログラムの役割、必要性について説明せよ 2 プログラムにおける変数と定数の役割を説明せよ。また、ローカル変数の有効な範囲について説明せよ。 3 C言語で使う変数が他について、宣言子と、printf関数、scanf関数それぞれにおいて対応する書式指定子を対応表にせよ。また、変数名を決める際に守るべき文法上の規則と、プログラマとして配慮すべき事項を説明せよ。 4 配列について、その役割と定義方法を説明せよ。 5 コンピュータにおける文字処理に必須なアスキーコードについて説明せよ。 6 C言語における文字列について、文字列定数、文字列変数を説明せよ。 7 C言語における繰り返し処理の文法(for,while,do~while)を、プログラムコード列を示して説明せよ。 8 C言語における条件判断の文法(if,else,else if)を、プログラム列を示して説明せよ。 9 繰り返し、条件判断において利用する論理式(等値演算子、関係演算子、論理演算子等で記迷する式)について、その記迷の方法を論理和、論理積も含めて説明せよ。 10 変数のアドレスについて説明せよ。また、ポインタについて、アドレスとの関連性を踏まえて、その役割と定義方法を説明し、具体的な使い方のプログラムコード例を示せ。 11 ポインタと配列の関係について、ポインタによる配列操作を列に説明せよ。 12 関数について、その役割と定義方法について説明せよ(戻りがた、関数名、引数リスト)。また、自作関数をそれらを利用するmain関数のプログラムコード例を示せ。 13 scanf関数の戻り値について、その内容を説明して、どのような際に利用すると便利か、プログラムコード例を示して説明せよ。 14 引数にポインタを利用する関数のプログラムコード例を示して、ポインタの必要性、重要性を説明せよ。 15 構造体について、その役割と定義方法を説明し、具体的な使い方のプログラムコード例を示せ。 16 ファイルポインタについて説明し、ファイル入出力の方法についてプログラムコード例を示して説明せよ。

  • C言語の構造体のサイズについて

    いつもお世話になっていります。 早速ですが、C言語の構造体のサイズについて教えてください。 typedef struct B { short code; char name; float price; } B; typedef struct A { B bbb[10]; double sougaku; } A; A aaa; といった構造体があった場合に、 sizeof(aaa.bbb.code) + sizeof(aaa.bbb.name) + … + sizeof(aaa.sougaku) という風に一つ一つサイズを取得し、合計して構造体のサイズを取得した場合と sizeof(aaa) という風に構造体のサイズを取得した場合のサイズの値が異なるといった現象が起きます。 その原因が分からなくて困っております。 そこで考えられる要因をお教えください。 因みに実際の構造体はサイズで言えば2500バイトくらいあります。 froat/char/double/short 型を使用しております。 よろしくお願いします。

  • 組込みでのC言語勉強法

    はじめまして。 最近、組込みのC言語を勉強しています。 処理速度の面や、可読性の良いプログラム、効率のよいプログラムを書けるようになりたいと思っています。 引数の数はレジスタで処理できる範囲におさめる事や、 構造体を使用するときにはポインタで渡すなど、 コードを書く際に気をつけるポイントがまとまってる書籍やHPなどを知りませんか? もしくは参考にすべき、サンプルコードなど知っていましたら、情報をいただけるとありがたいです。 よろしくお願いします。

  • EnumとType

    VB初心者です。 EnumやTypeについてよくわかりません。 何に使用するのでしょうか? また両者の違いについてもよくわかりません。 どなたかご教授ください。 ちなみにEnumは構造体でTypeは列挙型という認識はあっていますか?

  • C言語で構造体のメンバを簡単に出力する方法ありますか?

    いつもお世話になっています。 C言語の質問です。 単体テストログを取るために、 “関数Aをコールする前後で、関数Aに引数として渡す構造体のメンバをすべて”printf(もしくはfprintf)で出力して比較確認しなければならないのですが、 構造体のメンバが250とか、150とかあり、メンバ名もxxx_01,xxx_02などのようにエクセルなどで簡単に加工して作れるものではないので、いちいちメンバ名を指定しなければならないのでとても大変です。 オブジェクト指向言語なら、for each文とかでオブジェクトのメンバを簡単に取り出せるのでしょうが(間違っているかもしれません・・・)、C言語で構造体のメンバを、for文などのループを使って簡単に出力できる方法はないでしょうか? メンバの型は、一定ではなく、char、int、double、別の構造体のポインタ型(これは出力しなくて良い)と混在しています。メンバが全て同一の型ならポインタで構造体の先頭アドレスからsizeof(メンバの型)の分インクリメントしていけば出力できそうな気もしますが、メモリ上に連続して確保されるのかも私にはわからないので困っています。 enumで列挙して・・・というのも調べてみましたが、応用は出来ないようでした。 どなたか、地道にメンバ名を書いて出力する以外の方法をご存知の方、いらっしゃいましたらお知恵をお貸しください。 よろしくお願いいたします。 ※説明不足の点がありましたら補足いたします。

専門家に質問してみよう