int **restrict
Out、A、および B によってアドレス指定されたメモリが重複しないことのみをアサートします (ただし、関数がそれらのいずれも変更しないと仮定すると、A と B は重複する可能性があります)。これはポインタの配列を意味します。Out、A、および B が指すメモリの内容については何も主張しません。n1124 の脚注 117 には次のように記載されています。
識別子 p が型 (int **restrict) を持つ場合、ポインター式 p および p+1 は、p によって指定された制限付きポインター オブジェクトに基づいていますが、ポインター式 *p および p[1] はそうではありません。
と同様にconst
、two で修飾するとrestrict
、配列内のいずれの値もオーバーラップ メモリを指していないという、希望どおりの結果が得られるのではないかと思います。しかし、標準を読んでも、それが実際に有効であることを証明することはできません。「D を、オブジェクト P を型 T への制限修飾ポインターとして指定する手段を提供する通常の識別子の宣言とする」は、実際には for int *restrict *restrict A
、A[0] および A[1] がオブジェクトであることを意味すると思いますint への制限修飾ポインターとして指定されます。しかし、それはかなり重い法律用語です。
あなたのコンパイラが実際にその知識で何かをするかどうかはわかりません。明らかに可能です。実装されているかどうかの問題です。
rows * cols * sizeof(int)
したがって、 を割り当て、 でインデックス付けするだけの従来の C 2 次元配列に比べて、何が得られたのかはよくわかりませんA[cols*row + col]
。次に、restrict を 1 回だけ使用する必要があることは明らかです。これを使用して何かをrestrict
行うコンパイラは、Out への書き込み全体で A および B からの読み取りを並べ替えることができます。もちろん、なしrestrict
ではできません。したがって、自分がしていることを行うことで、コンパイラの慈悲に身を置くことになります。二重制限に対応できず、単一の制限ケースのみに対応できない場合、二重間接化により最適化が犠牲になります。
最初の推測では、とにかく、乗算は追加のポインター間接化よりも高速である可能性があります。明らかにパフォーマンスを気にするか、restrict をまったく使用しないため、この変更を行う前に (関心のあるすべてのコンパイラで) かなり慎重にパフォーマンスをテストします。アクセスするたびに配列に列があります。
A[0][col*nrows + row] undefined を介して要素にアクセスしていますか?
はい、要素がアクセスの 1 つによって変更された場合、これにより A[0] が A[col] を介してアクセスされるメモリのエイリアスになるためです。A と B のみが制限修飾されたポインターであれば問題ありませんが、A[0] と A[col] がそうである場合はそうではありません。
この関数では A を変更しないと想定しているので、実際にはそのエイリアスで問題ありません。ただし、Out で同じことを行った場合、動作は未定義になります。