最近のVisual C++ではC99もある程度サポートしているらしい。
- C99 library support in Visual Studio 2013 | Visual C++ Team Blog
- C++11/14/17 Features In VS 2015 RTM | Visual C++ Team Blog
- “Our C99 Standard Library implementation is complete, except for …” という記述がある。
上記ブログによると、 complex.h の関数もサポートしているらしい。しかし、コンパイラーは _Complex 型をサポートしていない。_Complex 型をサポートしていないのに、 complex.h の関数をサポートしているとはどういうことか。一体、 complex.h の関数は何を受け取って何を返すのか。
確認のため、次のような簡単な C++ のプログラムを書いてみた。
#include <stdio.h>
#include <complex.h>
#include <typeinfo>
int main(int argc, char *argv[]) {
puts(typeid(cabs).name());
}
結果は…。
double __cdecl(struct _C_double_complex)
どうやら、 _C_double_complex という構造体が定義されて、それが double _Complex 型の代わりをしているようだ。多分この構造体の中身は、要素数2の double の配列とかそんなんだろう。下記のコードは動いた。
#include <complex.h>
#include <stdio.h>
int main(int argc, char * argv[]) {
_C_double_complex z = {1.0, 1.0};
// z = _Complex_I; /* error C2440: '=': cannot convert from '_Fcomplex' to '_C_double_complex' */
printf("%g\n", cabs(z));
}
_Complex_I も定義されているようだが、型が違って、自動では変換されないっぽい。_C_double_complex はコンパイラー的には特別扱いも何もない普通の構造体のようで、四則演算とか double 型との変換は何もできない。
ただ、_C_double_complex 型とC99の double _Complex 型にはバイナリレベルの互換性はあるはずなので、 msvcrt を使うC99対応コンパイラーで msvcrt に含まれる C99 complex の関数を利用できる可能性はある。
MinGW からの利用
msvcrt を使うC99対応コンパイラーと言えば、MinGWだ。まずは、MinGWのリンク先CRTを msvcrt.dll (VC6)ではなく msvcr120.dll (VC2013)に変える。(本当は最新の msvcr140.dll にリンクしたいところだが、手元のMinGWにはインポートライブラリが用意されていなかった)
この辺を変えるには、 specs ファイルというのをいじればいいらしい。$ gcc -dumpspecs でデフォルトの specs ファイルを吐かせて、 -lmsvcrt という箇所を -lmsvcr120 に変える。
ただ、これだけでは cabs 等のC99関数はMinGW側が用意したものが使われてしまうようだ。MinGW側が用意した cabs 関数は libmingwex.a というファイルに含まれるようなので、これと msvcr120 をリンクする順番を入れ替える。
手順(MSYS2 の bash 上で実行):
$ gcc -dumpspecs | sed -e "s|-lmingwex %\{!mcrtdll=*:-lmsvcrt}|%\{!mcrtdll=*:-lmsvcr120} -lmingwex|" > msvcr120.specs
実際のプログラムで試してみる:
$ cat test.c
#include <complex.h>
#include <stdio.h>
int main(int argc, char * argv[]) {
double complex z = 1.0 + 1.0 * _Complex_I;
printf("%g\n", cabs(z));
}
$ gcc -std=gnu99 -specs=msvcr120.specs test.c
$ ./a.exe
1.41421
$ objdump -p a.exe | grep -i -A 40 msvcr120.dll
DLL Name: MSVCR120.dll
...
86b0 1082 _onexit
86ba 1147 _set_invalid_parameter_handler
86dc 1320 _unlock
86e6 1552 abort
86ee 1581 cabs ←msvcr120.dll の cabs 関数が使われている!
86f6 1590 calloc
8700 1674 exit
8708 1722 fprintf
...
参考にしたページ:MinGW GCCでlibcとしてmsvcrt.dll以外を使うまとめ – 自分についてのまとめサイト
結局
Visual C++ には _Complex 型のサポートはないし、MinGW には独自のC99サポートがあるし、やっぱり Visual C++ の complex.h の使いどころがわからん。別に、あったところで困るものではないが、なあ。
