restrict
修飾子は、呼び出された関数が渡されたメモリにアクセスする唯一の方法がlocalPtr
そのポインターfoo
を介することを意味します。そのメモリにはエイリアスはありません。これにより、別のポインターもデータを変更することを心配する必要がないため、オプティマイザーはより良いコードを生成できる可能性があります。
このコンテキスト、および他のほとんどのコンテキストでは、restrict
修飾子は、呼び出しを行っているプログラマーに責任を負わせ、「エイリアスなし」の要件を満たしていることを確認します。
上記のコードから目に見える危険はありません。
を使用する場合、ほとんどの場合、引数リストに複数のポインターがあることに注意してくださいrestrict
。C 標準から、以下を比較します。
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);
最初の ( memcpy()
) は、メモリのチャンクと[s1 .. s1+n-1]
オーバー[s2 .. s2+n-1]
ラップしてはならないことを示しています。実際にオーバーラップすると、未定義の動作が発生します。2 番目の ( memmove()
) はその要件を課していません。
foo()
しかし、データを変更している別のポインターを作成するための呼び出しではありませんか?
はい、いいえ、どちらかと言えば...しかし、ほとんどはいいえです。
のポインタfoo()
は確かに に渡されますbar()
が、が実行されている間、メモリにアクセスできるbar()
唯一の方法は、渡されたポインタを使用することです。bar()
したがってbar()
、動作しているメモリのエイリアスがないという前提でコンパイルできます。
コンパイラが を処理しているとき、引数が評価された後、関数が呼び出される前、および関数が戻るときに別foo()
のシーケンス ポイントがあることを認識 (確認) します。が渡されなかったためbar()
、データが によって変更された可能性があることを認識しています。したがって、これらの可能性を考慮したコードが生成されます。ただし、コンパイラは、によってアドレス指定されたメモリにアクセスできる唯一の方法は経由であることも認識しており(それが言うことです)、その仮定に基づいて処理を進めることができます。bar()
const char *
foo()
localPtr
localPtr
restrict
したがって、 がbar()
呼び出されている間にポインタの 2 番目のコピーが存在しますが、これは の規則に違反していませんrestrict
。