2

digraph と trigraph を学習していますが、理解できないコードがあります。(はい、非常に醜いことは認めます。)

このコードは次のようにコンパイルできます。

#define _(s) s%:%:s

main(_(_))
<%
    __;
%>t

このコードもコンパイルできます。

#define _(s) s??=??=s

main(_(_))
<%
    __;
%>

ただし、次の 2 つのコードはどちらもコンパイルできません。

#define _(s) s%:??=s

main(_(_))
<%
    __;
%>

#define _(s) s??=%:s

main(_(_))
<%
    __;
%>

これは私を混乱させます: コードの最初の 2 つの部分はコンパイルできるので、digraph と trigraph の両方の展開はマクロ展開の前に行われると思います。では、digraph と trigraph を一緒に使用するとコンパイルできないのはなぜですか?

4

2 に答える 2

2

ダイグラフとトリグラフはまったく異なります。Trigraph は、ソース コードがトークンに分離される前の翻訳のフェーズ 1 [注 1 を参照] で置き換えられます。ダイグラフは、他のトークンの代替スペルであるトークンであるため、ソースがトークンに分離されるまで意味がありません。(「digraph」という言葉はあまり正確ではありません。「trigraph」に似ているため使用されますが、digraph のセットに%:%:は 4 文字で構成されるものがあります。)

Soは、トークン分析が行われる前??=に a に置き換えられます。#しかし、%:は単なるトークンであり、 と同じ意味#です。

また、%:%:は と同じ意味のトークン##です。ただし%:#、2 つのトークン (%:および#) は正当ではありません。stringify 演算子 (%:またはのスペルに関係#なく) の後にはマクロ パラメーターしか続かないためです。#[注 2 を参照]がトライグラフ置換の結果であったとしても、それはそれほど違法にはなりません。

chqrlie's answer の陽気なスニペットで示されているように、ダイグラフとトリグラフの重要な違いの 1 つは、トリグラフが文字列でも機能することです。ダイグラフを使用すると、キーボードに角かっこや八角形がない場合でも C コードを記述できますが、それらの文字を出力するのには役立ちません。


注 (標準引用符):

  1. §5.1.1.2、翻訳フェーズ、パラグラフ 1:

    変換の構文規則間の優先順位は、次のフェーズによって指定されます。

    1. 物理ソース ファイルのマルチバイト文字は、必要に応じて、実装定義の方法でソース文字セットにマップされます (行末インジケーターに改行文字を導入します)。Trigraph シーケンスは、対応する単一文字の内部表現に置き換えられます。
  2. §6.10.3.2、# 演算子、パラグラフ 1:

    関数のようなマクロの置換リスト内の各 # 前処理トークンの後には、置換リスト内の次の前処理トークンとしてパラメーターが続きます。

于 2016-01-04T00:51:01.577 に答える
2

学術的な側面については、rici の十分に文書化された回答をご覧ください。

常識的な面では、あなたが C に習熟していない限り、digraphs と trigraphs はまったく役に立たず、この話題に時間を費やすべきではありません。これらは、メインフレームや一部のミニコンピューターで 1980 年代にまだ使用されていた非 US 7 ビット文字セットをサポートする方法として発明されました。これらの文字セットには、 、#{...}などのロケール固有の文字用のスペースを確保するために、C 言語に必要な句読点の一部が欠けていました(私のフランス語を許してください)。çéè

私が長い間使っていたこれらのシステムでさえ、トリグラフは決して使われませんでした。というのは、醜い実用的な選択肢が存在したからです: フランス語のシステムでは、éとのようなアクセント付きの文字が入力されましたが、C コンパイラによってとèとして解釈されました。これにより、C プログラミングが不明瞭になり、多くのプログラマーが US QWERTY キーボードとロケール (または同等のもの) に切り替えるようになりました。{}

これは過去のものであり、歴史的に興味深いだけであり、タイプミス、難読化、不快なインタビューの質問を除いて、実際にこれらを見ることはありません.

後者に関しては、これを投稿せずにはいられません:

fnmatch有効な日付を強制しても、日付テンプレートを検証できません。このコードの問題点は次のとおりです。

#include <stdio.h>
#include <fnmatch.h>
int main() {
    char date[] = "01/01/1988";
    if (fnmatch("??/??/????", date, 0))
        printf("invalid date format\n");
    return 0;
}
于 2016-01-04T01:18:37.527 に答える