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 とは対照的に、修飾子が要素だけでなく配列型に常に適用されるのは問題でしょうか?