15

C99仕様のパラグラフ6.7.3.8は述べています

配列型の指定に型修飾子が含まれている場合、配列型ではなく要素型がそのように修飾されます。関数型の指定に型修飾子が含まれている場合、動作は未定義です。

理論的根拠(論理ページ 87、物理ページ 94) では、フラット ポインターを (可変長) 配列ポインターにキャストする例が示されています。

void g(double *ap, int n)
{
    double (*a)[n] = (double (*)[n]) ap;
    /* ... */ a[1][2] /* ... */
}

確かに、配列apが関数内で変更されていない場合は、const とマークする必要がありますが、キャストは

void g(const double *ap, int n)
{
    const double (*a)[n] = (const double (*)[n]) ap;
    /* ... */
}

const(6.7.3.8 に従って) 配列型を持つターゲット自体ではなく、ターゲットの要素に適用されるため、修飾子を保持しませんdouble[n]-Wcast-qualこれは、適切なフラグ ( GCC 用) が与えられた場合、コンパイラが正しく文句を言うことを意味します。C で配列型を示す方法はありませんconstが、このキャストは非常に便利で「正しい」ものです。この-Wcast-qualフラグは、配列パラメーターの誤用を特定するのに役立ちますが、誤検出があるため、その使用を思いとどまらせます。インデックス付けa[i][j]はより読みやすく、多くのコンパイラではap[i*n+j]、前者よりも優れたマシン コードを生成することに注意してください。これは、前者の方が少ない分析で一部の整数演算を内部ループから引き上げることができるためです。

コンパイラはこれを特別なケースとして扱い、修飾子を要素から配列型に効果的に持ち上げて、特定のキャストが修飾子を削除するかどうか、または仕様を修正する必要があるかどうかを判断する必要がありますか? 割り当ては配列型に対して定義されていないため、6.7.3.8 とは対照的に、修飾子が要素だけでなく配列型に常に適用されるのは問題でしょうか?

4

3 に答える 3

6

これは、comp.std.c で過去 10 年間に数回議論されてきた既知の問題です。肝心なのは、あなたが提示した特定のケースは現在、標準 C では合法ではないということです。修飾子を削除するか、配列へのポインターを使用して配列内の修飾された要素を参照しないようにする必要があります。

この問題を解決するための良いアイデアがあると思われる場合は、news:comp.std.cディスカッションのために投稿できます。他の人がそれが良いアイデアであることに同意する場合は、あなたまたは他の誰かが欠陥レポートを提出して、動作を変更することができます (comp.std.c に頻繁に参加する委員会メンバーが何人かいるため、DR をレビューする可能性のある人々からのフィードバックは、提出する前に持っていると便利です)。修飾子が配列自体に影響を与えるというあなたの提案にはいくつかの問題があると思いますが、もう少し考えなければなりません。

于 2008-11-20T14:45:56.880 に答える
1

C プログラマ (コンパイラの設計者ではない) に可能な回避策:

gcc with-Wcast-qualはこれについて文句を言いません:

void g(const double *ap, int n)
{
    int i;
    struct box 
    {
      double a[n];
    };
    const struct box *s = (const struct box *)ap;

    for (i=0; i<n; ++i)
    {
       doStuffWith(s->a[i]);
       /* ... */
    }
}

さほどエレガントでなくても。末尾の配列メンバーaも、C89 と C99 の間でわずかに異なる意味を持ちますが、少なくとも意図した効果が得られます。

于 2008-11-20T13:46:49.277 に答える
0

ポインター (つまり、配列) の場合は状況がぎこちないのですが、詳細についての私の記憶は次のとおりです。

const double *ap定数 double へのポインターです。

double *const apdouble への定数ポインターです。

const double *const ap定数 double への定数ポインタです。

したがって、私は何年もこれを試していませんが、あなたが求めていることを実行することは可能だと思います-gccあなたが使用しているオプションは、私が最後にこれを行ったときに利用できませんでした!

編集:この回答は質問に対して正しくありません-以下のコメントを保持するために残しています。これは、単なる人間(またはさびたC開発者...)の問題を明確にします...)

于 2008-11-20T13:44:13.510 に答える