こんにちは、高木です。
ここのところPHPでC言語の前処理を行う話題が続いています。今回のその一環として、PHPでC言語の関数宣言を自動生成してみることにします。
今回は例として、標準Cライブラリのfgets関数の宣言を生成してみます。
| 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 37 38 39 40 41 | <?php $fgets_type = [   [     's' => 'char *',     'n' => 'int',   ],   'char *', ]; function make_signature(string $name, array $type): string {   // 返却値型の生成   if (count($type) > 1)     $return_type = $type[1];   else     $return_type = 'void';   // 仮引数並びの生成   $parameter_list = '';   foreach ($type[0] as $key => $value)   {     if (strlen($parameter_list) !== 0)       $parameter_list .= ', ';     if (is_array($value))     {       $paremeter_list .= "{$value[0]} {$key}[{$value[1]}]";     }     else     {       $parameter_list .= "$value $key";     }   }   if (strlen($parameter_list) === 0)     $parameter_list = 'void';   // 結果を合成する。   return "$return_type $name($parameter_list)"; } ?> | 
関数の型は仮引数並びと返却値型で構成されます。上記の$fgets_typeが関数の型を定義する配列にあたります。この配列は1~2要素で、0番目の要素には仮引数並びが、1番目の要素には返却値型を格納しておきます。配列の1番目の要素がなければ返却値は無いとみなします。0番目の要素が空の配列であれば仮引数が無いと見なします(0番目の配列は空でもいいので必須です)。
ここでfgets関数の宣言をおさらいしておきます。
| 0 1 2 | char *fgets(char *s, int n); | 
fgets関数は2つの仮引数sとnを受け取ります。そして、char*を返します。$fgets_typeはその通りに定義していますね。
そして、make_signature関数を使ってfgets関数の宣言を生成するには次のようにします。
| 0 1 2 3 4 | <?php echo make_signature('fgets', $fgets_type); ?>; | 
PHPの閉じタグ(?>)の直後にセミコロンがあることに注意してください。このセミコロンは、fgets関数の宣言の最後に付けるセミコロンです。関数を定義する際の関数頭部を生成する場合はセミコロンではなくブロックを書くようにすればいいでしょう。
今回の例では使っていませんが、仮引数の型には配列を指定することもできるようになっています。C言語では配列型の仮引数を指定してもポインタになってしまうのだから、ポインタでいいじゃないかと思うかもしれません。しかし、どうしても配列でなければならないケースがあるんです。
たとえば、次のようなケースです。
| 0 1 2 | void func(int n, char s[n], int array[static 10]); | 
上の例に登場する、仮引数sとarrayは配列として書く必要があります。
ほかには関数へのポインタ型をどうするのかという問題もあるのですが、あまりにも複雑になりすぎるのでtypedef名を付けるようにした方がいいでしょうね。
さて、こんなことをして何が嬉しいのかと思われるかもしれません。今回はあくまでも基本的な内容しか紹介していませんので、メリットを理解しにくかったかもしれません。次回は今回やった内容の応用を紹介しようと思います。



![[C11] 第9回 リテラル](https://www.kijineko.co.jp/wp-content/uploads/2021/10/2362788_s.jpg)


