プリプロセッサの上手な使い方

このQ&Aのポイント
  • C言語のプリプロセッサを上手に使ってソースコードを綺麗に整える方法について教えてください。
  • プログラムのソースコードを分割し、メイクファイルやパラメータ用のヘッダファイルを作成する場合は、どのような方法が上手いのか教えてください。
  • パラメータ用のヘッダファイルにはどのような設定を書くのが適切でしょうか?また、文字マクロはヘッダファイルで設定するべきなのでしょうか?
回答を見る
  • ベストアンサー

プリプロセッサの上手な使い方を教えて下さい

美しいソースを書けるようになりたくて日々自分のソースを見直しています。現在C言語を学習していますが基本的に独学なので、猛者な方々のご意見を伺いたいと思っています。 現在書いているプログラムが大規模になってしまったので、ソースを分割しまして、メイクファイルも作りました。何か条件を与えてそこからインクルードするファイルを選択したい、また静的にパラメータも与えたいというような場合、一般にどのようにするのが上手い方法なのか教えて頂きたく思います。メイクファイル、パラメータ用のヘッダファイル、ソースファイルの3つをそれぞれ下のように書いたんですが、一般にこういう書き方をしますでしょうか?自信が持てないでいます。猛者な方々のご意見をお待ちしています。長いソースのようですが、処理以前の問題です。よろしくお願いします。 パラメータして与えたいのは、 PBLOCK_PER_TBLOCK GRAINSIZE インクルードするファイルそのもの になります。これらは全てメイクファイルで設定するのが自然ですか?それともヘッダファイルで設定するものなのでしょうか?その場合、文字マクロもヘッダファイルで設定するものなのでしょうか? でも、ヘッダファイルで、 #define __KERNEL_SOA__ などと書いているのを見かけないと思うのですが。。。 //========================= メイクファイル ====================== ########### Please select encoding type ########### NFLAG = -D __KERNEL_AOS__ -D GRAINSIZE16 -D __USEDEVICE__ # NFLAG = -D __KERNEL_SOA__ -D GRAINSIZE16 -D __USEDEVICE__ # NFLAG = -D __KERNEL_AOS_INT__ -D GRAINSIZE16 -D __USEDEVICE__ # NFLAG = -D __KERNEL_SOA_INT__ -D GRAINSIZE16 -D __USEDEVICE__ # NFLAG = -D __USEHOST__ # for comparison ################# Makefile rules ################# CC = gcc RM = /bin/rm PROG = run OBJS = main_host.o etc.o (以下、省略) //============== パラメータ用ヘッダファイルparam.h ============= #ifndef _PARAM_H_ #define _PARAM_H_ ///////////////////////////////////////////// // you can adjust ///////////////////////////////////////////// /* Notice! Maximum size is 512. */ //#define PBLOCK_PER_TBLOCK ( 32 ) //#define PBLOCK_PER_TBLOCK ( 64 ) //#define PBLOCK_PER_TBLOCK ( 96 ) //#define PBLOCK_PER_TBLOCK ( 128 ) //#define PBLOCK_PER_TBLOCK ( 160 ) #define PBLOCK_PER_TBLOCK ( 192 ) //#define PBLOCK_PER_TBLOCK ( 224 ) //#define PBLOCK_PER_TBLOCK ( 256 ) //#define PBLOCK_PER_TBLOCK ( 288 ) //#define PBLOCK_PER_TBLOCK ( 320 ) //#define PBLOCK_PER_TBLOCK ( 352 ) //#define PBLOCK_PER_TBLOCK ( 384 ) //#define PBLOCK_PER_TBLOCK ( 416 ) //#define PBLOCK_PER_TBLOCK ( 448 ) //#define PBLOCK_PER_TBLOCK ( 480 ) //#define PBLOCK_PER_TBLOCK ( 512 ) ///////////////////////////////////////////// // you cannot adjust ///////////////////////////////////////////// #ifdef GRAINSIZE1 #define GRAINSIZE ( 1 ) #elif GRAINSIZE4 #define GRAINSIZE ( 4 ) #elif GRAINSIZE16 #define GRAINSIZE ( 16 ) #endif #define NUM_THREADS_ON_TBLOCK ( (16/GRAINSIZE)*PBLOCK_PER_TBLOCK ) //===================== ソースファイルmain.c ================== // includes, system #include <stdio.h> // include, configuration #include "param.h" // includes, sub program #ifdef __USEHOST__ #include <hostAES.cpp> #elif __USEDEVICE__ #ifdef __KERNEL_AOS__ #include <kernel_AoS.cu> #elif __KERNEL_SOA__ #include <kernel_SoA.cu> #elif __KERNEL_AOS_INT__ #include <kernel_AoS_int.cu> #elif __KERNEL_SOA_INT__ #include <kernel_SoA_int.cu> #endif #endif //////////////////////////////////////////////////////////////////////////////////// // Program main //////////////////////////////////////////////////////////////////////////////////// int main(int argc, char **argv) { ... main文内でNUM_THREADS_ON_TBLOCKを使いまわす (以下、省略)

  • g47040
  • お礼率55% (125/226)

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

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

ああそうだ, 「パラメータの値は変わってもソースが変更されない」と単純には make できないので「消してから make」とか「更新時刻を無視して make」とかしないとダメですね. となると, あんまり make の意味はないのかもしれません. あと, もとのプログラムで #ifdef GRAINSIZE1 #define GRAINSIZE ( 1 ) #elif GRAINSIZE4 #define GRAINSIZE ( 4 ) #elif GRAINSIZE16 #define GRAINSIZE ( 16 ) #endif はまずいかもしれません. コマンドラインで -DGRAINSIZE4 のように定義した場合, #elif でエラーになるかも. 「定義されているかどうか」を問題にするなら #if defined GRAINSIZE1 #define GRAINSIZE 1 #elif defined GRAINSIZE4 .... #endif のように defined を使うべきです. 下の #include するファイルを決めるところも同じ. なお, ここでは <~> はたぶん変 (おそらく "~" を使うべきところ) ですし, #include するファイルがすべての場合において 1つだけなら #if defined __USEHOST__ #define INCLUDE_FILE "hostAES.cpp" #elif defined __USEDEVICE__ #if defined __KERNEL_AOS__ #define INCLUDE_FILE "kernel_AoS.cu" (以下略) #endif #endif #include INCLUDE_FILE のように書くこともできます. おっと, 「_」で始まる名前も危険だ.

g47040
質問者

補足

有難う御座います。教えて頂いた方向性で修正してみたいと思います。 うまいこと修正できたら、ここにアップしてみたいと思います。

その他の回答 (1)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

とりあえず GRAINSIZE だけ, 1つの方針ですが: param.h は #if ! defined GRAINSIZE || (GRAINSIZE != 1 && GRAINSIZE != 4 && GRAINSIZE != 16) #error GRAINSIZE should be defined as 1, 4, or 16. #endif として, Makefile で GRAINSIZE = 16 NFLAG = -D __KERNEL_AOS__ -D GRAINSIZE=$(GRAINSIZE) -D __USEDEVICE__ とする. こうすれば, make のときに make -DGRAINSIZE=4 のように値を渡せますし, 何も書かなければ Makefile 中の値がデフォルトで採用されます. こうすると, 「値を変えても全くソースは変更しなくていい」ということになります.

g47040
質問者

補足

なるほど、かなり参考になります。どうも有難う御座いました!

関連するQ&A

  • define で 配列

    #defineで配列を定義したいのですがこのようなことは可能でしょうか? ヘッダファイル(test.h)で #define MAX (2) int A[MAX]={20,30}; ソースファイルで #include <stdio.h> #include "test.h" int main(){ int i; for(i=0;i<MAX;i++){ printf("A[%d]=%d\n",i,A[i]); } return 0; } とやれば出来るのですが、このヘッダファイルを複数のソースで参照すると 多重定義であるとおこられてしまいます。 #defineで #define A[MAX] {20,30} のように配列を定義する方法は存在するのでしょうか? どなたか良い方法を御存じの方、ご教授お願いします。

  • 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を用いた方法でお願いします。

  • ヘッダファイルの2重のインクルードについて

    ある書物に「ヘッダファイルを複数回インクルードすると、それを”再定義”することによるエラーになる」と書いてありますたが、以下のようなヘッダファイルを作りそれを数回インクルードしても何ら異状が無くコンパイルできました。 math.h→ヘッダファイル名 #define max(a,b)  ((a)>(b)?(a):(b))→ヘッダファイルの内容 c ファイル #include<stdio.h> #include"math.h"←複数回インクルード #include"math.h"←複数回インクルード int main(void){ int x=1,y=2; printf("max(x,y)=%d\n",max(x,y)); return 0; } 環境としては、RedHat Linuxでviです。 何ゆえ、エラーにならないのか良く解りません。 宜しくお願いします。

  • C言語のヘッダーファイルの作成方法

    Cの初心者です、宜しくお願いします。 下のようなヘッダを作成して、別のファイルに#includeして、走らせて見ました。 そこで疑問点ですが、 「mm」については置き替えが出来て、計算処理をしているのですが、「mm」の型宣言をしていません、これでもエラーにならないのは何故でしょうか。 普通に「mm」という変数とした場合(「mm」をヘッダーとして#includeしなかった場合)にはint型を宣言していないとエラーになると思うのですが。 また、「hh」については、そのまま「hh」がprintfされています。 文字の場合の置き替えは、使えないということでしょうか。 宜しくお願いします。 /*header_2.h*/ #define hh HEADER練習 #define mm 100 ================================================ #include "header_2.h" int main(void) { int aaa = 50 ; printf("%d\n\n" , mm); printf("hh"); printf("%d\n\n" , mm * 100); printf("%d\n\n" , mm * aaa); return 0; }

  • 他の.CPPファイルに定義した関数を呼び出す方法について

    新規作成したプロジェクトに、 以前自分が作成した.cppファイルと.hファイルを そのまま使えないかと考えています。 (※仮にそのファイルの名前を "define.cpp" "define.h" とします) プロジェクトに新規ファイル main.cpp を作成して、 define.hをインクルードし、 以下のようなテストのプログラムを組みました。 ・../util/define.cpp---------------------- #include <iostream> #include "define.h" void test(){ std::cout<<"test."<<std::endl; } ・../util/define.h------------------------ #pragma once void test(); ・main.cpp---------------------------- #include "../util/define.h" int main(){  test();  return 0; } 上記のソースを VisualC++7.0 でビルドすると、 main.cppの3行目で以下のようなエラーが出ました。 > LNK2019: 未解決の外部シンボル "void __cdecl test(void)" が関数 _main で参照されました VisualC++で「既存項目の追加」という項目より、 実体の定義されたdefine.cppをプロジェクトに追加していないため 当然といえば当然なのですが・・・ C言語でいうところの<stdio.h>等みたいに、 わざわざプロジェクトにCPPファイルを追加しなくても 関数を呼び出せるようには出来ないのでしょうか? 全ての関数と処理をヘッダーファイルに記述すると解決ですが 物凄く見辛いのでそれは避けたいのです。 また、色々なPC間で使っているため(学校のPCなので)、 ツール自体のプロパティを弄らない方法があるのでしたら、 多少面倒でもそちらの方が好ましいです。 追加する方法があるかどうか、 あればその方法をご存じでしたら教えていただければ嬉しいです。 よろしくお願いします。

  • 複数ファイルに分割した時の構成について

    大学の卒論にむけてプログラムを書いていて、一つのmain.cでは長くなってきたので、関数を func1.h func1.c のような別ファイルに記述することにしました。 その現在の構成を、質問欄の下部に簡単に書いたので、構成が自然かどうか意見をお聞きしたいです。特に、 「include文、define文をヘッダファイルにまとめて、各ファイルからincludeしている構造」がコードの記述方法として、きもちわるくないか、一般的かどうか、教えてください。 このようにした理由は、 ・defineマクロを多くのサブ関数で利用している。 ・define定義の値を細かく変えながら実行し、結果の違いを出力したい。 ・その為、各ファイルの頭にdefine定義を置いた場合、定義の値を  いちいち全てのファイルで変更しなければならなくなり、面倒…。 →defineマクロをdefine.hにまとめた。ついでに、<stdio.h>,<math.h>なども置いてしまえばスッキリするかも~。 という経緯です。 理学の学科でまわりに詳しい人がいなく、 プログラム知識もほぼ独学なので、不安に感じて質問しました。 よろしくおねがいします。 +++++++++++++ 以下が、簡単なファイル構成です +++++++++++++ -----define.h----- #include <stdio.h> #include <math.h> #define A_MAX 3 #define B_MAX 5 -----main.c---- #include "define.h" int main() { func1(); func2(); func3(); } -----func1.h---- #include "define.h" void func1(int hoge); //プロトタイプ宣言 -----func1.c---- #include "func1.h" void func1() { hogehoge; } ------func2以下、func1と同構造

  • 分割コンパイルの初歩

    C言語ですが、.hに実装を書くのは避けたほうが良いといわれます。 私は main.c define.h aaa.h bbb.h みたいなスタイルでコードを書いていました。 まずdefine.hでグローバル変数や、マクロなどの宣言を まとめて行い、ほかの.hやmain.cでも使えるようにして いました。 しかし、以下のような状況のとき、どのように分割すれば 良いのかが分かりません・・・。 たとえば、以下のように、マクロNUM、変数a,bをすべてのファイルで共有して使えるように分割コンパイルするにはどのようにコードを書き直せば良いのでしょうか? //--------------main.c------------------ #include "define.h" #include "aaa.h" #include "bbb.h" int main( void ){   printf("%d", a);   printf("%d", b);   printf("%d", NUM);   aaa();   bbb();   return 0; } //------------define.h------------------ #define NUM 100 int a = 10; int b = 20; void aaa( void ); void bbb( void ); //------------aaa.h------------------ void aaa( void ){   printf("%d", a);   printf("%d", b);   printf("%d", NUM); } //------------bbb.h------------------ void bbb( void ){   printf("%d", a);   printf("%d", b);   printf("%d", NUM); }

  • 分割コンパイルについて

    現在分割コンパイルが分からずに苦戦しています。 下記のリストは構造体を使わなければコンパイラを通すことができましたが、 使うとなぜか通りません。 あれこれ試しましたがどうしても分かりません。 何がおかしいのでしょうか? *define.hで全てのファイルへの定義や宣言を行わせています。 ////////////// //Main.cpp ////////////// #include <stdio.h> #include <conio.h> #include "define.h" int main( void ){ Tmp[0].c = 15; printf("a: %d\n", a); printf("b: %d\n", b); printf("c: %d\n", Tmp[0].c); printf("NUM:%d\n", NUM); aaa(); bbb(); getch(); return 0; } ////////////////// // A.cpp ///////////////// #include <stdio.h> #include "define.h" void aaa( void ){ printf("a: %d\n", a); printf("b: %d\n", b); printf("c: %d\n", Tmp[0].c); printf("NUM:%d\n", NUM); } ////////////////// // B.cpp ///////////////// #include <stdio.h> #include "define.h" void bbb( void ){ printf("a: %d\n", a); printf("b: %d\n", b); printf("c: %d\n", Tmp[0].c); printf("NUM:%d\n", NUM); } ////////////////// // define.cpp ///////////////// #include "define.h" int a = 10; int b = 20; struct Parameter { int c; }; struct Parameter Tmp[NUM]; ////////////////// // define.h ///////////////// #define NUM 100 extern int a; extern int b; extern struct Parameter Tmp[NUM]; void aaa( void ); void bbb( void );

  • include無しにclassが書けない

    粗末な質問タイトルで申し訳ありません。 Visual C++2010で、includeを書かずにclass宣言を行おうとすると「Error:PCH警告」が発生します。 この理由をご教授ください。 IntelliSense: PCH 警告: 適切なヘッダー停止位置が見つかりません。 というエラーメッセージが表示されるのですが、これはプロトタイプ宣言がないときに発生する警告らしいですね。私が書こうとしているソースコードを次に示します。 -----main.cpp---- class TestClass {}; int main(void) { return (0); } ----------------- このソースで、"class"の部分に赤波線が引かれて先述のエラーメッセージが表示されます。 このソースの先頭に#include<iostream>なり#include<stdlib.h>なり何かインクルードを記述すると警告はなくなります。 しかしクラスはその枠のみですし、ライブラリ関数も何も使用していないのでとくに必要なインクルードファイルも何もないと思うのですが、どうしてこのようなエラーが発生するのでしょうか。 あと、蛇足になりますが、本来はクラス宣言部分を別のヘッダーファイルに分けたいのです。 クラス宣言部分を別のヘッダーに分離してヘッダーの先頭に #pragma once を記述するか、分離したヘッダをmain.cpp内でインクルードしてもエラーは解消されます。 (何からもインクルードされなかったらエラーになる) もう何が何やらさっぱりわからないです><

  • なぜgccはstdio.hをインクルードしなくてもprintfが実行できるのか

    なぜgccはstdio.hをインクルードしなくてもprintfが実行できるのでしょうか。 暗黙にインクルードされるヘッダと されないヘッダファイルの差分等あれば教えていただきたく。。 // main.c int main(){ printf("SWSW\n") ; return 0 ; } % gcc main.c % ./a.out SWSW

専門家に質問してみよう