定数M_PIが使えない
能書き
かなり間があいたので、小ネタ。
毎度ながら、知ってる人にとっては当たり前の内容を有難そうに書く。
遭遇したエラー
例えば、次のようなコードを書いたとする。
まあ、半径から円の面積を計算するだけの、よく見るコードだ。
ただし、円周率を自前で定義しているあたり、このコードはモダンでない。
_USE_MATH_DEFINESフラグを立ててcmathをインクルードしたほうがよい。
上記のコードのdefine文を単に置き換えると次のようになる。
しかし、このコードをコンパイルすると... 次のようなエラーが出る。
error C2065: 'M_PI': 定義されていない識別子です。
error C2065: 'M_PI': undeclared identifier
原因と対策
実はこれ、ヘッダファイルを読み込む順序が問題なのである。
エラーが出たコードでは、フラグを立てる前にiostreamを読み込んでいた。
iostreamヘッダのインクルードを追ってみると:
- iostreamは、istreamをインクルードしている。
- istreamは、ostreamをインクルードしている。
- ostreamは、iosをインクルードしている。
- iosは、xlocnumをインクルードしている。
- xlocnumは、cmathをインクルードしている。
巡り巡って、iostreamをインクルードすると、cmathが読み込まれる。
もちろんその時点では_USE_MATH_DEFINESフラグは立っていない。
解決策は、次のとおり。
マクロの順序を変更しただけ。
ヘッダファイルに関するフラグは、include文より前に定義しよう。
雑記:前もって定義されている数学定数
#define _USE_MATH_DEFINES
フラグを立ててcmathをインクルードすると、次の数学定数を利用できる。
ネイピア数含め対数周りの定数と、円周率に関する定数。
一番下の定数を、M_1_SQRT2と改名すべきと思うのは私だけだろうか?
雑記:ぼやき
iostreamに、cstdlibやcmathがインクルードされてるっていったい何なんだ。
いわゆる神モジュールになっている気が...