• ベストアンサー

ソースとヘッダについて

VC++2008を使っています。これは他でもいえるのではないかと思いますが、一応プロジェクトの種類はWindowsFormアプリケーションです。 字数削減や書きなおしを楽にするために、ある程度のマクロを織り交ぜたコーディングをしたいのですが ソースに#defineしたものの効果範囲は、#undefの場所まで あるいはそれがなければそのソースの終了地点まで でしょうか? もしそうなら、ソースに書く分なら「別のソースに同じマクロを、全く違う定義をして使っても問題ない」という事でしょうか? ヘッダに書いた場合は、なんか#undef文を下の方に書いてもまるで上に書いたかのように「駄目」という判定になってしまったのですが、かといって#undefを書かないとそのヘッダをインクルードする他のヘッダにも影響を与えてしまうようで… これをどうにかできる方法はありませんか? また、ソースでは #pragma once などをしなくてもいいのですか? (あるいは書いてもソースはオブジェクトファイルに変換され、実質的にはコンパイル後に影響が出るため、プリプロセッサはコンパイル前に完了するので、ソースにこれを書いたところで無意味ということでしょうか?)

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

  • ベストアンサー
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.7

C++/CLI系の文法には詳しくないので内容には触れませんが、 #define き tree #define せ き->SelectedNode #define か TN^ a=(TN^)せ #define あ Nodes->Add #define れ if (!a) return これはまたすごい・・・。半年とか経つと自分でなぜこうしたか忘れないか私は不安ですが。普通マクロ名は、機能を表す名前を使います。理由は忘れるから。 じゃあ、同じソースコード内でも前半と後半でおなじ「き」でも意味が違うってコードを考えているんですね。 その1。いちいちエディタでカーソルかざさないと機能が確認できないのは可読性が低いのが問題かと。 2.#dafineで定義されたものが増えてくると混乱するかも。 3.マクロを多用するとプログラムコードが増大する(今時のメモリなら気にしなくて良いが)のと、マクロ内でエラーが発生するとデバッガのカーソルが止まるのはマクロの名前の部分なので、どの部分か判断に困りますのでそこが気になるかな。 まぁ、他の人に見せるコードじゃなければ何をやって良いのですが、一度やってみて作れるか作れないか、可読性が良いかは自分で判断すればよいと思います。デバッグで困ったり一月後に読めなくければ大丈夫かと。 #define ご(x,y) if (x) goto y; まぁ、構文的には普通ですがgotoはあまり多用しないほうがと要らぬお節介を書いときます。 >「同じソース」には「#pragma onceを書いたファイル自身」をプリプロセッサが一回しかincludeをしないでOKですか? コンパイルの単位=ソースコード内に一回しか#includeさえません。 >そして、「同じヘッダにも」その効果は適用されますか? #includeのファイルがネストしていても同じです。 #include "a.h"と成っていてa.h内で#include "b.h"だとしたらa.hとb.hに各々「#pragma once」が書かれていれば一回しかインクルードされません。 >そしてもしそうならつまり、ソースあるいはヘッダが異なればそれぞれで「一回ずつは許容される」という意味になりますよね? いえヘッダがヘッダをインクルードしている場合は、違うと思うんですけどね。実験したことが無いので試してみてください。 >ということは、逆に言うと#pragma onceをつけないヘッダなら、同じファイル内で複数回includeしてもOKになる、ということでしょうか? 同じ定義を#undefなしに#defineするとエラーになりますけどね。 >む?よく考えてみるとところで……ソースファイルは、インクルードする方法はあるのでしょうか? #includeは実は何でもインクルードできます。 #include "aa.cpp"もOKです。

LongSecret
質問者

お礼

はい、実はgotoについては( )と2つの引数(?)の実験として作ったという意味合いの方が強く、これを使おうと思う場合は結構限られてて 「沢山のif()~があって、それが同じような結果を出す場合で、try catch にしたくない場合」 「何層にもなったループ文の内側の方から、一定の状況の時に一気に抜け出したい場合」 ぐらいです。 なので、消しても問題ないぐらいだとは思っています。 他で充分同等に書けるようなところでgotoを多用すると可読性下がる可能性高し!というのは納得ですからね。 残りの事につきましても、納得しました。ありがとうございます!

LongSecret
質問者

補足

あ!いい事思いつきました。 万が一それでも忘れた場合の事を考えて「以下の理由づけをコメントでそれらdefineの右側にでも書いておけばいい」ですよね? そうすれば万が一忘れても、また一回見れば「ああ、そうそう」 で、それ以後またそれでやっていけますので…。 おかげさまで思いつけました。ありがとうございます。 (早速メモっておこう。)

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (15)

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.5

なんか、目的が↓の入賞でも目指してるような感じに見えます。 http://www.ioccc.org/main.html #見た目で意味が取れないdefineは一般的に邪道です それはさておき。 #pragma once は、「複数回インクルード宣言があった場合でも、最初の一回しか読み込まない」ということです。 #要は多重インクルードガード なので、 > つけないヘッダなら、同じファイル内で複数回includeしてもOKになる というのは正反対の誤った理解です。 逆に何も対策していないファイルを複数回インクルードしたら多重定義エラーが多発しますね。

LongSecret
質問者

お礼

ありがとうございます。 >見た目で意味が については、問題ありません。 ・「き tree」は一瞬で分かります。 ・「せ き->SelectedNode」は、「せ」はSelectedNodeおよび「選択されているノード」のどちらでも「せ」なので分かります。 ・「か TN^ a=(TN^)せ」は「きゃ」(cast)でもよかったのですが、打つ時三文字なので「型」「変える」の「か」にしました。 ・「あ Nodes->Add」は、しょっちゅう書いてた「Add」の「あ」です。 ・「れ if (!a) return」は「return」の「れ」です。 なお、これらは実際よく使うので定義しました。 一度意味が分かると簡単で --------------------- か, ^b = gcnew TN; れ; a->Level ? a->Parent->あ(b) : き->あ(b); b->あ(a=a->CopyN()); せ = a; b->Expand(); --------------------- こういう風に、字数がかなり少なくて済むのと、「ひらがなとかはdefine」という自分用ルールを作っておくことで これらが「define」であることも一瞬で分かり しかも せ = a; などは 「ああ、ツリービューの選択ノードを『TN^ a』にするんだな」 と、一瞬で分かります。 >というのは正反対の誤った理解です。 >逆に何も対策していないファイルを複数回インクルードしたら多重定義エラーが多発しますね。 はい、確かに普通と逆転の発想だとは思いますが、しかし結果としてはそうですよね? 「ソースファイルではundefしなくてもほかに影響はない」 ならば define専用(および、一括undef専用)のファイルを作っておき「それをソースファイルのみに使う」とでもすれば、多重定義エラーはしないのではないでしょうか?

全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.4

なにか意図を聞いたほうが良いようですね。#defineマクロで同じ名前のものをソースコード毎に違う機能や値として使いたいのはどんな場合ですか? プロでも仕方なく書く場合がありますが、基本的にバグになるので避けます。どのように使うか聞かせてください。

LongSecret
質問者

お礼

う~ん 具体的な別利用方法の細部については決まっていないのですが 物凄く見通しが良くなった事例があったので、例えば.NET FrameworkのTreeNodeを継承したTNクラスを作り、さらにTreeView^ treeを用意したとして こういうものを使うつもりです。 #define き tree #define せ き->SelectedNode #define か TN^ a=(TN^)せ #define あ Nodes->Add #define れ if (!a) return これは、後で .NET FrameworkのTreeNodeやTreeViewクラスに相当するものを自作しようと思っていますが、その場合も、似せて作れば使いまわせるかな?とも思っています。 それとかこういうものも #define ご(x,y) if (x) goto y; こういう風に文字数が少ないと、もしかしたらいつか不足するかも(漢字を使えばいいかもしれませんが)と思いまして…

LongSecret
質問者

補足

あとは下記 >#pragma once について 以下の内容の真偽が分かれば最高です。 これらの解釈で問題ないでしょうか?

全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.3

>もしかして #define や #pragma once など、プリプロセッサについては、ソースであってもヘッダであっても、全部コンパイル前(あるいは同時…?)に処理されるのでしょうか? プリプロセス(前処理)とは、コンパイル前に行われる処理です。だから#inlucdeコードの挿入も#defineの置き換えもも全てコンパイル前に完了します。

LongSecret
質問者

お礼

ありがとうございます。 よかった やはりそうですよね? 最初そう思ってたんですが、質問をする直前に「あれ?」ってなって、質問後また混沌とし、やっとこれで落ち着けた形です。

全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.2

>ソースに#defineしたものの効果範囲は、#undefの場所まであるいはそれがなければそのソースの終了地点まででしょうか? その通りです。連続したソースの中に無いとだめです。 >もしそうなら、ソースに書く分なら「別のソースに同じマクロを、全く違う定義をして使っても問題ない」という事でしょうか? C/C++としては問題ないですが、同じ意味で違う値を持つことを意識的に行う場合を除いては危険なので避けます。同じ名前なのに値が違うことは、思い込みで錯誤が生まれやすくバグを生み出す要因だからです。 >ヘッダに書いた場合は、なんか#undef文を下の方に書いてもまるで上に書いたかのように「駄目」という判定になってしまったのですが、かといって#undefを書かないとそのヘッダをインクルードする他のヘッダにも影響を与えてしまうようで… ヘッダ中だけ有効な#defineをしたいと言う事でしょうか?可能なはずですが。 ---- xx.h ---- #define AA 1 // この間だけ有効 #undef AA >また、ソースでは#pragma onceなどをしなくてもいいのですか? #pragma onceは同じソースに#includeをプリプロセッサが一回しかしないという意味です。ソース自体はどこにも#includeしていないなら意味がありません。

LongSecret
質問者

お礼

ありがとうございます。 >C/C++としては問題ないです という部分が分かれば大丈夫です。ややこしすぎるのは避けますが、自分で管理するなら、場合によっては「えげつないまでの字数削減」のために、例えばひとつのものに2種類の意味を割り当てるぐらいの範囲なら大丈夫かなと思っています。 (一つのファイルに一つなら、マウスカーソルをその上に乗せれば内容が表示されますし、エラーが出ればどこがそうなったかである程度判断できると思うので、さして気にするほどの事はないかなと) >可能なはずですが。 はい、可能ですよね? おかしいなぁ…確かに今やってみると出来るのですが さっきはなぜ出来なかったのだろう…? たぶん、何か別の要因があったんですよね。 出来ると分かれば、問題はありませんし。 >#pragma once について つまり下の言葉と合成しますと 「同じソース」には「#pragma onceを書いたファイル自身」をプリプロセッサが一回しかincludeをしない でOKですか? そして、「同じヘッダにも」その効果は適用されますか? そしてもしそうならつまり、ソースあるいはヘッダが異なればそれぞれで「一回ずつは許容される」という意味になりますよね? ということは、逆に言うと#pragma once をつけないヘッダなら、同じファイル内で複数回includeしてもOKになる、ということでしょうか? む?よく考えてみると ところで…… ソースファイルは、インクルードする方法はあるのでしょうか?

全文を見る
すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「ソースの終了地点」というのが今一つどこをさしているのかわかりませんが, それが「マクロを定義したファイルの最後」であれば違います. #define の有効範囲は #undef があればそこまで, それがなければ「コンパイル単位の最後まで」です. これはインクルードしていようとなんだろうと同じ. ちなみに「ヘッダに書いた場合は~」のところは, 概念的な例でいいので出してもらえると解説しやすいな. まさか, 単に「インクルードしているので『ヘッダファイルの下の方』でもソースファイルとしては『上に書いたかのようにみなされる』」ってことじゃないよな? #pragma once は「1回しかインクルードしない」ということを意味していたような気がする. つまり, 「インクルードされる」可能性のあるファイルじゃないと無意味.

LongSecret
質問者

お礼

ありがとうございます。 「ヘッダファイルの下の方云々」については どうも奇妙なことに、私の手違いによる勘違いだった可能性が高いです。 どういう場合だとだめでどういう場合だとよかったのか、同じつもりでやったら先ほど出来てしまったので、逆にいろいろ試しすぎて何で引っ掛かったのか正確に思い出せません…(すみません) ただ、可能性の一つとしては別々のヘッダで別々の定義をした同じ名前のマクロが、それらをインクルードしたときに名前がかぶってしまうため、undefがそのいずれかに含まれる場合 位置によってインクルード順を入れ替えないと失敗する…といった類の話だった、かもしれません。 >ソースの終了地点 につきましては、私の質問の意図としてはその通りです。 その…「ソース」の実装については「コンパイルの後」という解釈だったので、「コンパイル単位の最後」というのが良く分かりません。 もしかして #define や #pragma once など、プリプロセッサについては、ソースであってもヘッダであっても、全部コンパイル前(あるいは同時…?)に処理されるのでしょうか? そして、いずれにしてもソースで#defineした場合、あるいはそのソースでしか#includeしないヘッダで#defineしたものを#includeした場合は、最後まで#undefとしなくても そのソースはそのままではほかに影響を及ぼさないため そのままで問題ないのでしょうか? あとインクルード についてなのですが こちらは#pragma onceと違って、#defineのように 行が関係ある、という事であっていますか?

LongSecret
質問者

補足

そして… なるほど #pragma onceは 「自分自身」に対して効果があるんですね? 今まで「それを書いたファイルに#includeするファイルすべてに適用される」と勘違いしていました。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 新規ソース内のマクロ定義が既存ソース内のマクロ定義と衝突しない策について

    C言語です。 Effective C++か何かで読んだ const int hoge = 3; const char *bar = "HOGEHOGE"; などを使用しようと思ったのですが、 C言語ではコンパイルする際に、 「関数の外では定数は宣言できません」?? のようなエラーが出てしまいました。 そこでこれらを使用するのは諦めて、 #define~を使って定数を使用しました。 (上記のようなエラーが出てしまうのは、 C言語の仕様上、文法がおかしいからだと 思います。そもそもC++に関する本に 載ってるtipsだし^^;) #defineを使用するように修正して、コンパイルする際に、 既存のソース上のマクロ定義(#define~)と名前が重複するものが いくつか見つかり、修正に手間がかかりました。 マクロ定義なので、スコープという概念は 適用されないと思うので、既存のソースと新規のソースで マクロ定義がバッティングしないようにする策としては どのようなものがあるでしょうか? 今のところ思いつくものとしては以下です。 ・新規のソースに関するキーワードをプリフィックスとして使用する ・新規のソースの末尾で#undefをする。(これは試してないので有効か  どうか自信がありません。) 他に何か有効な策がありましたら教えてください。 よろしくお願いいたします。

  • 関数の実体定義にヘッダファイルの2重定義防止方法が効かない?

    いつもお世話になっています。 MFCでCプログラミングをしています。 ヘッダファイルの2重定義防止のために、 ヘッダファイル全体を下記のように 囲みました。 <aaa.h> #ifndef AAA #define AAA #define PI 3.141592 void Func(); int wa(int a, int b){ return a+b; } #endif ビルドしたところ、 関数宣言(Func)や#define部分(PI)については、 2重定義が防止されているようなのですが、 関数の実体部分(関数wa)については、 2重定義防止機能が働かず、 ***.obj : error LNK2005: "int __cdecl wa(int a, int b)" は既に ***.obj で定義されています。 というリンクエラーが表示されます。 関数の種類や ヘッダファイル内の宣言の順番を いろいろ変えてみたのですが同じ結果でした。 ここで、このヘッダファイルの先頭に #pragma onceを使用すると このリンクエラーは回避されるのですが、 他コンパイラとの互換性の観点から、 #pragma once以外の方法で実現する必要があるので、 困っています。 URLを検索してみたのですが、 このような特殊な場合について記述されているものは 見つけられませんでした。 どなたか解決法又はヒントをご教示頂ければ ありがたいです。 よろしくお願いします。

  • VisualC++のプリプロセッサ定義とビルド関係

    VisualC++のプロジェクトには「#define _MYDEBUG」というプリプロセッサと同じ働きをするプリプロセッサ定義という設定項目がプロジェクトのプロパティにありますが、これらがコンパイラによって使用されるタイミングはどのようなものでしょうか? VisualC++コンパイラがソースパーズ時にプロジェクトのプリプロセッサ設定を参照しに行ってコンパイル結果に反映させるといったことが行われているのでしょうか?

  • defineで定数が置き換えられない?(C言語)

    #defineについて質問です。 #defineは、ソースコード内にこの文字を見つけたら、コンパイルする前にこの文字をこの定数に置き換えて、というプリプロセッサですよね?だから、printfで#defineで定義した定数を出力する場合で、変換指定が必要ない場合は #include <stdio.h> #define DEF 100 void main(){ printf("#defineで定義された定数はDEFです"); } でもいいと思うんです。ですがこのソースコードは間違いで、実行結果は #defineで定義された定数はDEFです(←置き換えられてない) となってしまします。プリプロセッサだけ実行しても、DEFは100に置き換えられずそのままです。printfで#defineで定義した定数を出力させたい場合は書式指定をしなければなりません。なぜ、このような場合は#defineで定義した定数は置き換えられないのでしょうか?回答よろしくお願いします。

  • C言語でヘッダファイルを自作する

    C言語で#defineを用いてヘッダファイルを作成したのですが、 作成したコンパイルするときにヘッダファイルがオープンできません。 参考にしている資料があるのですが、そこに書かれているサンプルプログラムを 丸ごとコピーして作ったプログラムも同様にヘッダファイルがオープンできない というエラーが出るので、ヘッダファイルを定義する方法そのものが間違っていると 思うのですが、どこが間違っているのでしょうか? よろしければ正しい記述方法もお教えください。 #include <stdio.h> #if !defined SAMPLE_H #define SAMPLE_H wa(int a, int b) { return a+b; } #endif #include "sample.h" int main(){ printf("%d\n",wa(40,70)); return 0; } ヘッダファイルの定義の方法は他にもあるとは思いますが、 今回は#defineを用いた方法でお願いします。

  • ヘッダーファイルについて

    //DMusic7Ex.h あるプログラムを解析しています。 //コンパイラ設定 //多重定義防止 #pragma once //ファイルインクルード #include <dmusicc.h> #include <dmusici.h> //型定義 typedef IDirectMusicPerformance* LPDIRECTMUSICPERFORMANCE; typedef IDirectMusic* LPDIRECTMUSIC; typedef IDirectMusicLoader* LPDIRECTMUSICLOADER; typedef IDirectMusicSegment* LPDIRECTMUSICSEGMENT; //関数プロトタイプ 1・DMusic7Ex.cppを作らず他の関数で、このヘッダーファイルをインクルードする手法は一般的なのか? 2・なぜ関数プロトタイプを記述しないで、このタイプ宣言を他のファイルで使用するのは一般的なのか?

  • C言語の#defineについて

    初歩的なことですみませんが、 #define命令はソースのどこに記述しても問題ありませんか? 一応、コンパイル時には問題ないようですが。 また、#ifdef,#ifndef,#elseifとうのマクロ全般においてはどうなのですか? どなたか教えていただけませんか?

  • プリプロセッサのエラー対策がわからない状態

    こんにちは。 VS.2005でプログラミングをしているのですがプリプロセッサで起こるエラーの対策が分からずに 悩んでいます。 エラー内容は以下のとおりです。 warning C4067: プリプロセッサ ディレクティブの後に余分な文字がありました - 改行が必要です この状態を改善するには、/ZaコンパイラオプションがどうのこうのとMSのHPには載っていますが どのようにやればいいのか分かりません。 以下にソースコードを載せておきます。 #ifndef _TEXT(x) // TEXTマクロを使うとこの警告が表示されるようです。 #define _TEXT(x) __T(x) #endif この警告を無くすにはどうしたらいいでしょうか? よろしくお願いします。

  • 前処理指令行の末尾の改行の必要性

    ある本に次のような例題がありました。 「不正なヘッダ」 #define max(a,b) ((a)>(b)?(a):(b)) EOF 「正しいヘッダ」 #define max(a,b) ((a)>(b)?(a):(b)) ←Enterキー EOF ここで”不正なヘッダ”でコンパイルするとエラー表示のメッセージが表示され、その理由は”前処理指令は改行文字で終了しなければならない”との事です。又処理系によっては”不正なヘッダ”(改行文字なし)が許されるものもあると書かれていました。しかしその場合、可搬性は損なわれると書いてありました。私の処理系はRedHat Linuxでviを使っています。私の処理系で”不正なヘッダ”でコンパイルしてもなんらメッセージが無くコンパイルできました。 はたしてこの場合可搬性はあるのでしょうか? 又その本には”ソースファイルの最後の行にも必ず改行文字をつけよう”と書いてありました。しかしviを使っていてcプログラムとしてソースファイルを書いている時、最後に改行文字を入れた事はありませんでした。この場合も可搬性は失われるのでしょうか。 宜しく願います。

  • C言語における定数の使用方法

    こんにちは。 今日質問したいのは、タイトルにありますように、C言語における「定数」の使い方についてです。 私は現在、Visual C++を用いてC言語のプログラミングを勉強しているのですが、条件文(if文)に定数を用いてコーディングを行おうとしても、どうしてもエラー表示が出て、うまくコンパイルすることができません。 具体的には、 if(No>=1 && No<=10){ //具体的な処理部分 } というif文を、予めヘッダファイル内にて定義した定数 #define start 1; #define stop 10; を用いて次のように、 if(No>=start && No<=stop){ //具体的な処理部分 } コーディングしたいと考えています。 しかし、これをコンパイルするとエラーが発生してしまいどうにもうまくいきません。 また、定数ではなく数字で記述するとうまく回ります。 別のところで定数を、 wk = start; のように代入で使用しているのですが、そこではなにも問題がありません。 いったい何が間違っているのか、どのようにすればうまくいくのかを教えていただきたいと考え、書き込ませていただきました。 皆様、どうぞよろしくお願いします。