Trigraph

やっぱりマニアくらいしか知らない仕様があって、例えば C の Trigraph なんてのがあります。

これは、# とか \ とか [] とか無い文字セットしかない場合でも C のコードが書けるようにという ANSI規格化のときに追加された配慮で、以下のような対応になっています。

    Trigraph     Equivalent
    ========     ==========
      ??=            #
      ??/            \
      ??'            ^
      ??(            [
      ??)            ]
      ??!            |
      ??<            {
      ??>            }
      ??-            ~

Digraphs and trigraphs - Wikipedia

この Trigraph を使うと、例えば

#include <stdio.h>

int main( void )
{
    char hello_str[] = "hello,world";
    int i;

    for (i = 0; i < sizeof(hello_str) -1; i++)
    {
        printf( "%c\n", hello_str[i] );
    }

    return 0;
}

なコードは、

??=include <stdio.h>

int main( void )
??<
    char hello_str??(??) = "hello,world";
    int i;

    for (i = 0; i < sizeof(hello_str) -1; i++)
    ??<
        printf( "%c??/n", hello_str??(i??) );
    ??>

    return 0;
??>

なエレガントなコードに大変身するわけです。(よ、読めない...)

どう考えても これは C の 暗黒面なので、普段気にすることは全くないです。というか知らない方が良い仕様であるわけですが、極々 まれに悪さをしてくれるのです。というのも、Trigraph の置換は コメント中や文字列中でも 行われてしまうので、例えば

// comment???/

で次の行もコメントになっちゃうとか、"??<" みたいな文字列を扱えないとか が起きるわけです。

なので gcc なんかでは Trigraph 置換 はデフォルトで OFF に成っています。で、たまたまこんなコードをビルドすると

#include <stdio.h>

int main( void )
{
	printf( "??<hogehoge??>" );
	return 0;
}
> gcc main.c
main.c:5:11: warning: trigraph ??< ignored, use -trigraphs to enable
main.c:5:22: warning: trigraph ??> ignored, use -trigraphs to enable

>a
??<hogehoge??>

と怒られて ??? となるわけです。(無視されるので実際の出力は置換されません。良い挙動だー)なお、gcc で Trigraph を有効にするには -trigraphs オプションを付けます。

> gcc -trigraphs main.c

> a
{hogehoge}

当然怒られないし、出力結果は置換されてしまいます。(いきなりコッチをやられた方が訳がわからなくなるかも)


* * *


こんな風に 実際に使いどころがあるのか非常に怪しい Trigraph ですが、上記の様な問題があるとなれば放って置けません。なので C99 にて あらたに Trigraph の欠点を補う Digraph が導入されました。

    Digraph     Equivalent
    =======     ==========
      <:             [
      :>             ]
      <%             {
      %>             }
      %:             #
      %:%:           ##

....なんでそんなにこだわるのさorz.

でもっ!コレ、意外に結構イけてるんですにゃ。混乱の元だった コメントや文字列リテラルの中での置き換えは無効になってます。そして、なんといっても最大の改善点はコレ

%:include <stdio.h>

int main( void )
<%
    char hello_str<::> = "hello,world";
    int i;

    for (i = 0; i < sizeof(hello_str) -1; i++)
    <%
        printf( "%c\n", hello_str<:i:> );
    %>

    return 0;
%>

うーん、実に読みやすい(ぉ

イけてるのでgcc も そのままビルドを通してくれます。