15


2

Cの定数配列型、標準の問題?

C99仕様書の段落6.7.3.8

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

rationale(論理ページ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;
    /* ... */
}

(6.7.3.8により)配列型が double [n]`のターゲット自体ではなく、ターゲットの要素に適用されるため、 `const`修飾子は保存されません。 これは、適切なフラグが与えられていれば、コンパイラは正しく文句を言うことを意味します(GCCの場合は `-Wcast-qual)。 Cで `const`配列型を表す方法はありませんが、このキャストは非常に便利で「正しい」です。 `-Wcast-qual`フラグは配列パラメータの誤用を識別するのに役立ちますが、誤検出はその使用を勧めません。 `a [i] [j]`のインデックスは読みやすく、多くのコンパイラでは `ap [i * nj]`よりも優れた機械語コードを生成します。より少ない分析。

コンパイラはこれを特別な場合として扱うだけでよいでしょう。与えられたキャストが修飾子を削除するのか、それとも仕様を修正するべきかを判断するために、修飾子を要素から配列型に効果的に持ち上げます。 代入は配列型に対して定義されていないので、6.7.3.8とは対照的に、修飾子が要素だけではなく常に配列型に適用されるのは害になりますか?

3 回答


6


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

この問題を解決するのに良い考えがあると思うなら、議論のためにそれを `news:comp.std.c`に投稿することができます。 他の人がそれが良い考えであることに同意するならば、あなたまたは他の誰かが欠陥レポートを提出して振る舞いを変更することができます(comp.std.cを頻繁にする委員会メンバーがいるのでDRを見直す人々からのフィードバックそれを提出する前に持っておくと便利です)。 修飾子を配列自体に影響を与えるというあなたの提案にはいくつか問題があるかもしれませんが、私はそれをもう少し考えなければならないでしょう。


1


Cプログラマーのための考えられる回避策(ただしコンパイラー設計者ではない):

`-Wcast-qual`を指定したgccはこれについて文句を言いません:

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; ia[i]);
       /* ... */
    }
}

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


0


状況はポインタ(つまり配列)では厄介ですが、ここで詳細を思い出してください。

`const double * ap`は定数倍精度へのポインタです。

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

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

なので私は何年も試していませんが、あなたが求めていることを実行することは可能であると私は信じています - あなたが使っている `gcc`オプションは私が最後にやったときには使えませんでした!

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