こんにちは、高木です。
引き続きPHPでC言語の前処理を行う話題になります。前回、前々回で、PHPからC言語の型の情報を取得する方法について解説しました。今回は、C言語では同じ型であっても別名が付いていることがあるので、元の型名というか、配列定数C_LIMITSのキーに使える型名に変関数方法について考えていきます。
C言語で型に別名を付ける方法の代表格はtypedefです。標準ライブラリでもtypedefを使った別名がいくつも定義されています。具体例を挙げると、size_t, ptrdiff_t, wchar_tなどなどです。これらの対応表を次のような配列定数で定義してあげることにしましょう。
0 1 2 3 4 5 6 7 8 9 10 |
<?php define('C_TYPEDEFS', [ 'size_t' => 'unsigned long', 'ptrdiff_t' => 'long', 'wchar_t' => 'int', 'wint_t' => 'unsigned int', 'char16_t' => 'unsigned short', 'char32_t' => 'unsigned int', ]); |
これはあくまでも定義の一部です。ほかにも必要なだけ配列の要素を追加していく必要があります。GCCやClangであれば、次のようにすればtypedefで定義される内容をある程度把握することができます。
0 1 2 |
echo | gcc -E -dM -x c - | grep _TYPE__ |
上記はGCCの場合です。Clangであれば、gccの代わりにclangコマンドを使うだけです。結果は以下のように出力されます(どんな型に定義されるかは環境によります)。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#define __UINT_LEAST8_TYPE__ unsigned char #define __SIG_ATOMIC_TYPE__ int #define __UINTMAX_TYPE__ long unsigned int #define __INT_FAST16_TYPE__ long int #define __INT_FAST64_TYPE__ long int #define __UINT8_TYPE__ unsigned char #define __INT_FAST32_TYPE__ long int #define __UINT_LEAST16_TYPE__ short unsigned int #define __SIZE_TYPE__ long unsigned int #define __INT8_TYPE__ signed char #define __UINT32_TYPE__ unsigned int #define __INT_LEAST16_TYPE__ short int #define __UINT_LEAST64_TYPE__ long unsigned int #define __UINT_FAST16_TYPE__ long unsigned int #define __CHAR16_TYPE__ short unsigned int #define __INT_LEAST64_TYPE__ long int #define __INT16_TYPE__ short int #define __INT_LEAST8_TYPE__ signed char #define __INTPTR_TYPE__ long int #define __UINT16_TYPE__ short unsigned int #define __WCHAR_TYPE__ int #define __UINT_FAST64_TYPE__ long unsigned int #define __INT64_TYPE__ long int #define __WINT_TYPE__ unsigned int #define __UINT_LEAST32_TYPE__ unsigned int #define __INT_LEAST32_TYPE__ int #define __UINT64_TYPE__ long unsigned int #define __INT_FAST8_TYPE__ signed char #define __UINT_FAST32_TYPE__ long unsigned int #define __CHAR32_TYPE__ unsigned int #define __INT32_TYPE__ int #define __INTMAX_TYPE__ long int #define __PTRDIFF_TYPE__ long int #define __UINTPTR_TYPE__ long unsigned int #define __UINT_FAST8_TYPE__ unsigned char |
この結果から自動生成することもできますが、この程度なら手作業でやってもいいかもしれませんね。
型に別名を付ける方法はtypedefだけではありません。先ほどの出力結果のようにマクロを使って別名を付けることもできます。C言語の標準ライブラリでも、マクロを使った型の別名定義が行われています。具体的にはboolマクロがそうです。ですので、配列定数C_TYPEDEFSに次の要素を追加することにしましょう。
0 1 2 |
'bool' => '_Bool', |
さらに、別名の定義とは違いますが、算術型は同じ型であっても型指定子の表現が複数あります。たとえば、long型であれば、次の11通りの表現が考えられます。
0 1 2 3 4 5 6 7 8 9 10 11 12 |
long long int int long signed long long signed signed long int signed int long long signed int long int signed int signed long int long signed |
こうした別名の配列定数C_TYPEDEFSの要素として追加しておくとよいでしょう。
0 1 2 |
'long' => 'long', |
上記のような要素は一見必要なさそうですが、いっしょに追加しておけば型名の変換処理を完結にできます。
配列定数C_TYPEDEFSの自動生成は、手間の割には得るものが少ないですので、手作業でやった方がいいでしょうね。