9

C99には複合リテラルがあり、次のように関数に渡すことができます。

f((int[2]){ 1, 2 });

ただし、fが関数ではなく関数のようなマクロである場合、プリプロセッサが1つの引数としてではなく、「(int[2]){ 1」と「」の2つの引数として解析するため、gccはこれをバーフし2 }ます。

これはgccまたはC標準のバグですか?後者の場合、それは関数のようなマクロのすべての透過的な使用をほぼ除外します。これは大きな欠陥のようです...

編集:例として、以下が適合プログラムフラグメントであることが期待されます。

fgetc((FILE *[2]){ f1, f2 }[i]);

ただしfgetc、マクロとして実装できるため(引数を保護し、複数回評価しないようにする必要がありますが)、このコードは実際には正しくありません。それは私には驚きのようです。

4

3 に答える 3

10

この「バグ」は、C89以降の標準に存在しています。

#include <stdio.h>

void function(int a) {
    printf("%d\n", a);
}

#define macro(a) do { printf("%d\n", a); } while (0)

int main() {
    function(1 ? 1, 2: 3); /* comma operator */
    macro(1 ? 1, 2: 3);    /* macro argument separator - invalid code */
    return 0;
}

私は実際にこの解析をチェックするために標準を調べていません。gccの言葉を取り入れましたが、非公式に、最初のステートメントを機能させるには、演算子の優先順位と引数リストの構文の両方に一致:する必要があります。?2番目のそのような運はありません。

于 2011-04-05T22:28:27.757 に答える
6

これはC標準に準拠しており、C ++の場合と同様に、次の問題があります。

f(ClassTemplate<X, Y>) // f gets two arguments:  'ClassTemplate<X' and 'Y>'

C99で括弧を追加することが合法である場合は、次を使用できます。

f(((int[2]){ 1, 2 }));
  ^                ^

C99§6.10.3/11からのこの動作を指定するルールは次のとおりです。

最も外側の一致する括弧で囲まれた前処理トークンのシーケンスは、関数のようなマクロの引数のリストを形成します。

リスト内の個々の引数はコンマ前処理トークンで区切られますが、一致する内括弧の間のコンマ前処理トークンは引数を区切りません。

于 2011-04-05T20:35:53.843 に答える
1

それがバグである限り、それはgccではなく標準にあります(つまり、この点で、gccは標準が要求することを実行していると思います)。

于 2011-04-05T20:36:56.493 に答える