#ifdef
が1つの場合には、そのon/offだけで2通りのコードをテストしなくてはなりません。
#ifdef
が2つの場合には2^2=4になります。
#ifdef
が5つの場合には2^5=32になります。
こうなってくると
手作業でビルドして32通りをテストするのは困難になります。
#ifdef
はモジュールのファイル構成にかかわる部分にだけになるよう減らすこと。
const bool DebugInfo = true;
if(DebugInfo){
//冗長な表示をするコード
}
を以下のように書く必要はありません。
#ifdef DEBUG_INFO
showDebugInfo(); //冗長な表示をするコード
#endif
ビルド後の実行形式が大きくなってしまうことを気にしないのであれば
デバッグ専用のコードを #ifdef
#endif
で囲うのをやめてしまえば可読性はよくなります。
(CppUnitなどで単体テストを強化すれば、開発のメインのプログラムの中にデバッグ専用のコードを埋め込むことが減るはずです。
また、プログラムのテストが十分行われていれば、最後にデバッグ用のコードを生成しないように、不要なコードを削除するのは容易です。ですから #ifdef
を使って、ソースコードの改変を発生させるのは、最小限に減らしましょう。
)
#ifdef DEBUG_INFO
showDebugInfo(); //冗長な表示をするコード
#endif
みたいなコードが、ソースコードに何十箇所も出てくる場合には、
その部分のコードを全て有効にしていたうえで、 showDebugInfo()
関数の中でだけ、 #ifdef DEBUG_INFO
を使うことです。
void showDebugInfo(){
#ifdef DEBUG_INFO
//冗長な表示をするコードの実体
#endif
}
そうすれば、DEBUG_INFO
のマクロ定数の使用する場所が減ります。
マクロ定数をC++の定数に代入しておき、
値が参照できれば十分なときには
#ifdef マクロ定数
#endif
の代わりに
if( /*C++のbooleanの定数*/ ){
}
を使うと、 #define
の結果によって構文が乱されることがなくなります。
効果
ソースコードを改変していったときに、試してみなかった #ifdef
の組み合わせで、ソースコードがビルドできないという問題を減らすことができます。
追記
#ifdef
がOSの違いに起因する場合
ディレクトリの有無を調べるbool型の関数を作る場合、C++ではOSの違いによってコードが異なります。そこで、よくとられる手法は、OSの違いを含みうる部分を1つのソースファイルに集めて、その範囲の中で #ifdef
を用いることです。そして、単体テストを移植対象のOSでそれぞれ実行することです。そうすると、OSの違いが他の #ifdef
の組み合わせを考える必要がなくなります。
2のべき乗で、テストする組み合わせが増えていくことを防止できます。
OSの違いによるコードが存在する場合、まずBoostのライブラリに該当するものがないかを調べてみよう。
ファイルシステム
boost::filesystem
ネットワーク関係
boost::asio
Boostのライブラリを使えば、OS依存性のあるコードは大幅に減らせるはずです。
Boostのライブラリは、あなたが自作するライブラリよりは格段にテストされているはずです。
Boostのライブラリを使えば、Windowsでテストしておいた結果からLinuxで動作する可能性が格段に高いと期待されます。
自作ライブラリで #ifdef
#else
#endif
しているコードでは、windowsで動作させたからといってLinuxで動作するかどうかはわかりません。
以上の理由からBoostを使うように強く推薦します。
次のような記述を見つけました。
「条件コンパイルが避けられない場合もあるが、これはプラットフォームのバリエーションに対応するときの最終手段だと考えるべきだ」(『テスト駆動開発による組み込みプログラミング C言語とオブジェクト指向で学ぶアジャイルな設計』p.247)
#ifdef
などのようなプリプロセッサがない言語で開発できる場合には、そのような言語に移行するという手もあるだろう。
GO 言語はそのような言語の選択肢の1つだ。