このブログは、旧・はてなダイアリー「檜山正幸のキマイラ飼育記 メモ編」(http://d.hatena.ne.jp/m-hiyama-memo/)のデータを移行・保存したものであり、今後(2019年1月以降)更新の予定はありません。

今後の更新は、新しいブログ http://m-hiyama-memo.hatenablog.com/ で行います。

C/C++ 定義済みのプリプロセッサ定数による判断、推論方法

ユーザーの明示的な定義に依らないで、出来るだけコンパイラがセットするプリプロセッサ定数(マクロ定数)を使いたい。判断したいことは、

  1. コンパイラが何か?
  2. 32ビットか64ビットか?
  3. MFCが使えるか?
  4. Win32 APIが使えるか?
  5. Windowsプラットフォームか?

すべて独立な(直交する)概念ではなくて、絡んでいる。

このなかで、ビット数は32ビットオンリーなので、マクロ定数でゴチャゴチャしないで、サイズをsizeofで測ってマズイと思ったらstatic_assertで中断する。

↑が参考になる。自分のgistにコピーした。↓

MSCの情報は、

次の記事も参考になる。

コンパイラの種類
  • MSCなら、 _MSC_VER が定義されている。
  • gccなら、__GNUC__ が定義されている。

今のところ、これだけでいい。

MFCが使えるか?
Win32 APIが使えるか?
  • 使えるなら、_WIN32 が定義されている。これはgccでも定義されるので、コンパイラの種類を気にすることなく判断できる。
  • ただし、Windows.h などのヘッダが、MSCGCC(さらにmingwとTDM)で違う/コンパイラSDKのバージョンで違う、つう可能性はある。
Windowsプラットフォームか?

これが厄介。問〈とい〉の立て方が「Windowsプラットフォームか?」というのが不適切な気がする。プラットフォームを問題にしている、というより、「Win32 APIを使う or 使わないで済ませる」の差。

  • _WIN32 が定義されていても(つまり、Win32 API使えても) 、使いたくないときがある。

コンパイル時の意志によって切り替える。次の状況と選択がある。

  1. OSがWindowsでWin32 APIが使える ので、使う。
  2. OSがWindowsでWin32 APIが使える が、使わない。
  3. OSがWindowsではない ので、Win32 APIを使えない。

ユーザーが意志を示すなら、USE_WIN32 のような定数を明示的に指定することになる。しかし、デフォルトが「使う」だとすると、否定である NO_WIN32 の導入が良さそう。

推測の方法

デフォルトは、「MSC, Win32, MFC使用」だから、これを否定する NO_WIN32, NO_MFC 定数を導入する。gccだからといってWindowsではない、とは言えない。

  1. NO_WIN32 ⇒ NO_MFC : 逆は成立しない
  2. __GNUC__ ⇒ NO_MFCgccMFCを使うことはないだろう
  3. !_MSC_VER ⇒ NO_MFC : 上の規則より強い。が、gccしか使わないなら上の規則と同値。
  4. !_WIN32 ⇒ NO_WIN32 : _WIN32が定義されてないなら、実際 Win32 APIは使えない。

問題は、NO_WIN32を結論するための前提が !_WIN32 だけか? ということ。_POSIX_SOURCE, _ANSI_SOURCE があれば、公的な規格ではないプラットフォーム固有の機能を使うべきではない、という意思表示だと思う。そうなら、

だろう。

順番を考慮してまとめると:

  1. !_WIN32 | _POSIX_SOURCE | _ANSI_SOURCE ⇒ NO_WIN32
  2. NO_WIN32 | !_MSC_VER | !_MFC_VER ⇒ NO_MFC

[追記]二番目の前提に、!_MFC_VER を追加。MSVC Express Editionだと、MSCではあるが、MFCが付いてない。そのときは、NO_MFCをセットすべき。[/追記]

その他

あと、開発中かリリースかはNDEBUGだけで判断。ユーザー定義の定数は出来るだけ作りたくない。

開発中にしか意味のないソースがあったなら、全体を #ifndef NDEBUG …… #endif しておいて、リリース時には空っぽになるようにしておくといいかも。