質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

Q&A

解決済

3回答

7541閲覧

型修飾子 restrict の意味を教えて下さい

tails

総合スコア22

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

0グッド

1クリップ

投稿2020/09/13 13:49

JIS X 3010 : 2003 6.7.3.1 restrict の形式的定義
を確認しましたが、この内容がどういう理論なのか、理解できませんでした。
同じブロック内で restrict 修飾のあるポインタが同じオブジェクトを指さないことを保証している、といったふわっとした理解しかできていません。
どなたか、分かりやすく解説いただけないでしょうか。

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

「保証している」というより「プログラマが保証する」という意味です。

メモリ領域が重なる可能性があることで最適化が制約される場合があり、重なる可能性がないことをプログラマはわかっているから積極的に最適化してよいというヒントとして restrict は機能します。

また、関数の仮引数に restrict が付いていれば領域が重なる可能性があるものを渡してはいけないというコメントのような役割にもなると言えるでしょう。 例えば memcpyvoid *memcpy(void * restrict s1, const void * restrict s2, size_t n); と宣言されているのでこの型を見るだけで範囲が重なってはならないことが一目瞭然なわけです。

投稿2020/09/13 16:06

SaitoAtsushi

総合スコア5466

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tails

2020/09/17 21:11

そのようなことはなんとなく分かるのですが、JIS に書いてある形式的定義と、それがどのように対応しているのか分かりませんでした。
guest

0

これは、コンパイラが、より最適化したコードを出力できるようにするための機能です。

例えば「メモリバッファをコピーする関数を作る」という要件を実装する必要があった時に、この要件だけでは領域が重なっているかどうかがわからないためmemmove()を使う必要があります。

でも、この要件に加えて、渡される2つのバッファのポインタにrestrictが付いていれば、お互いの指すバッファが重ならない(自身のポインタ経由以外では更新されないので、相手のポインタで更新されることはない、すなわち領域が重なっていない)ことがわかるので、memcpy()が利用できます。こちらの方が一般的には高速です。

このような判断を、コンパイラ内部でできるようにするためのものです。

ググっただけなので恐縮ですが、こちらの解説はいかがでしょうか。
https://programming-place.net/ppp/contents/c/057.html#restrict

投稿2020/09/13 16:01

segavvy

総合スコア958

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tails

2020/09/17 21:11

そのサイトの内容は分かりやすかったです! 適切な使い方は理解できました。 ありがとうございました。
segavvy

2020/09/17 23:48

お役に立てたようで良かったです!
guest

0

ベストアンサー

そこの例にあるようなvoid f(int n, int * restrict p, int * restrict q)
という宣言だったとすると、「関数f内でpを使ってアクセスするメモリ領域と、qを使ってアクセスするメモリ領域が重なって、なおかつ重なっている部分を更新する」ということが無いことをプログラマがコンパイラに対して保証するために付ける修飾子です。

これを保証することでオブジェクトコードの最適化が行えると言うことでしょう。

この修飾子を付けたのに、上記括弧内のようなことが発生するような引き数を渡すと、動作は未定義と言うことですね。

投稿2020/09/13 17:00

otn

総合スコア84712

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tails

2020/09/17 21:18

回答ありがとうございます。 実際にmemcpyのようなものを作り、restrict有りと無しでアクセスするメモリ領域が重なるような渡し方をして、最適化してみたのですが、特に実行結果が変わらないようです。 もちろん未定義の動作なので特に動作が変わらないというのもあると思いますが、実際に変わる様子を見てみたいです。 環境は、 CPU: Intel Core i7-4712MQ OS: Windows 10 64bit コンパイラ: cl(Visual Studio), gcc(MinGW), gcc(WSL) です。 どのようなコードとコンパイラの最適化の組み合わせで動作が変わる様子を確かめてみることができるでしょうか。
otn

2020/09/18 09:47

実行結果と言うより、生成されるコードに差異があるかどうかですよね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問