C++ ときどき ごはん、わりとてぃーぶれいく☆

Wonder Rabbit Projectのなかのひとのブログ。主にC++。

Visual Studio 2019 C++: _DEBUG _WINDOWS _WIN32 _WIN64 _UNICODE NDEBUG WIN32 WIN64 UNICODE のメモ

シンボル 自動的に定義される?(predefined macro?) VSが新規作成で構成に追加? そもそも何? 効果ある?(*2)
_DEBUG yes ( msbuild ) yes ( Debug ) デバッグビルドを意味する識別用にmsbuild がプロジェクトの Configuration -> Advanced -> Use Debug Libraries が Yes で /LDd /MDd /MTd が有効になる場合に自動的に定義される。但し、プロジェクト作成時にConfiguration(Debug) -> C/C++ -> Preprocessor -> Preprocessor にも明示的に追記される。 yes
_WINDOWS no (*3) yes Windows向けを意味する識別用の定義。プロジェクト作成時にConfiguration -> C/C++ -> Preprocessor -> Preprocessor に明示的に追記される。(*3) no
_WIN32 yes ( cl ) no Windows の 32-Bit 版または 64-Bit 版で動く事を意味する識別用に cl によって自動的に定義される。 yes
_WIN64 yes ( cl ) no Windows の 64-Bit 版で動く事を意味する識別用に cl によって自動的に定義される。 yes
_UNICODE yes ( msbuild + ps ) (*1) yes UNICODEの使用を意味する識別用にプロジェクト作成時に自動的にプロパティーシートとして設定が追加され、 Configuration -> C/C++ -> Preprocessor -> Preprocessor に追記される %(PreprocessorDefinitions) を介する形で追加される。実行効果的としては Win32 API や _T マクロが W になったりする。 yes
NDEBUG no yes ( Release ) デバッグビルドではない=リリースビルドを意味する識別用の定義。プロジェクト作成時に Configuration -> C/C++ -> Preprocessor -> Preprocessor に明示的に追記される。 yes
WIN32 no yes ( x86 ) Windows の 32-Bit 版向けを意味する識別用の定義。プロジェクト作成時に Configuration -> C/C++ -> Preprocessor -> Preprocessor に明示的に追記される。 (*4) nope, ... yup... (*4)
WIN64 no no WIN32に対応したWIN64の定義について何か仕様があるような気がしてユーザーが定義する事のある何か。 no
UNICODE yes ( msbuild + ps ) (*1) yes UNICODEの使用を意味する識別用に定義される。プロジェクト作成時に _UNICODE と一緒に同様に追加される。 no

(*1): プロジェクト作成後に構成のプリプロセッサーの定義から $(PreprocessorDefinitions) を削除または;区切りを忘れて無効となる書き換えを行ったりすると Character Set に Use Unicode Character Set を設定していても定義されなくなってしまうので少しそのあたりの取り扱いには注意が必要です。

(*2): この列における「効果」は Windows SDK で分岐に使われていたりする効果です。例えば WIN64Visual Studio が直接扱ったり Windows SDK にそれを使うコードが含まれたりはしていませんが、しばしばユーザーが独自に定義して使用している事はあります(たいてい_WIN64を使った方がよいとは言え実際にWIN64が使われているコードもしばしば遭遇します)。

(*3): 一見、 _WIN32_DEBUG のように predefined macro のような気配を持っていますが、違います。Visual Studio はプロジェクト作成時に _WINDOWS を構成へ自動的に追記(VS .net 以降 VS 2019 現在まで)しますが、実際のところ意味はありません(対象プラットフォームが Windowsソースコード#if する用途では _WIN32 が一般的に使われていますし、 predefined macro なのでそちらの方が安心です)。 Windows SDK では内部的に _WINDOWS_ というよく似た定義は使っていますが _WINDOWS は使っていません。

(4): VS2019 の時代では(おそらく)完全に MSDN などの Microsoft 公式の情報がオンライン上に現存しないアンドキュメント化&実行効果的にもおまじない化したゆるふわ CPP 定義のようにも思え…ますが、実は現行の Windows SDK の一部でも実際に使われているので、 Win32 API の一部は WIN32 を明示的に追加定義してビルドしないと期待動作しない可能性があります。具体的に言うと WinSock2.h を使いたい場合とか。WIN32 が未定義の場合、 Windows SDK の一部のヘッダーでは 16-Bit 時代の Windows 向けにコードが分岐したりします。ごく一部の機能を使わなければ WIN32 を定義しなくても現行の Windows SDK のほとんどの機能は問題無く使えます。しかし、執筆現在の時代では、公式な資料がオンライン上に現存 しません(たぶん)(5)。

(*5): 著者の記憶からこの定義の存在について歴史的経緯を思い出してみると、 Visual C++ 6.0 かもう少し後くらいの時代に、それまで WIN32 を使う事になっていた"お約束"をMicrosoftが「これからは_WIN32を使おうよ」と変更した…とかあったような気がしないでもないような…どうだったかな…的な何かです。そういえばもうずいぶん昔、 cygwinmingw の環境から winsock2 を使う必要があったときにちょっとだけ WIN32 に "おこ" した気もしますが…もうほぼ思い出せる記憶はありません…。

WIN32 に関する明確な仕様や歴史的経緯のわかる資料についての情報提供の呼びかけ

私が C++ を"当時のドシロウトなり"でもそれなりに使うようになったのは実質的には Microsoft Visual C++ 6.0 からです。それ以前は Microsoft Visual Basic 4.0 から 6.0 時代までの旧式(.netではない)の Visual BasicWindowsGUI アプリを作っていました。処理速度の限界に耐えられなくなり、 C++ デビューした昔ばなし…はまた機会があればメモを残す事にします。

当時は C++ の言語仕様と VC++ 6.0 の言語標準からのずれがどうこうとごちゃごちゃ言えるほどの知識も無く、CD-ROMで配布されていた MSDN (当時のMSDNは翻訳クオリティーがまともだったので日本語でも読みやすかったし、謎のリンク切れも無く快適だったのです…)が教科書みたいなものでした。

そのような次第なので、私の当時やそれ以前の C++VC++ に関する知識は存在しないか、後付けで勉強したか、または想像が記憶を捏造してしまっている可能性も十分にあります。それで、今回気になったために ↑ のような情報提供の呼びかけをふんわりしてみたのでした。

追記: このメモはなんなの?

VS2019でC++プロジェクトを扱う際に、MSVC++での開発で頻出するCPPマクロ定義について、"じっさい"のところ構成などで明示的に定義する必要がある/ないを判断する参考用です。構成が多数あり複雑になりがちな場合に少しでも保守コストを軽減したい、そんなときに何が要らないか気になったので整理しました。