web-dev-qa-db-ja.com

配列添え字内に表示される「volatile」キーワードの目的は何ですか?

Cppreferenceを参照しているときに、次のような関数パラメーターに奇妙な型の配列がありました。

void f(double x[volatile], const double y[volatile]);

それで、配列添え字内に現れるvolatileキーワードの目的は何ですか?それは何をするためのものか?

43
msc

volatileキーワードは、関数パラメーターの配列型を宣言するために使用されます。

ここで、double x[volatile]double * volatile xと同等です。

cppreference は言う:

関数宣言では、キーワードvolatileは、関数パラメーターの配列型を宣言するために使用される角括弧内に表示される場合があります。配列型の変換先のポインター型を修飾します。次の2つの宣言は、同じ関数を宣言しています。

void f(double x[volatile], const double y[volatile]);

void f(double * volatile x, const double * volatile y);

この構文は、関数パラメーターのC言語でのみ有効です。

40
msc

一般に、このC(およびCのみ!)機能を使用すると、配列括弧内に任意の型修飾子を指定できます。正確な標準引用は次のとおりです。

'' type of array ''としてのパラメーターの宣言は '' typeへの修飾ポインター ''に調整されるものとしますここで、型修飾子(存在する場合)は、配列型の[および]内で指定されたものです)派生。キーワードstaticが配列型派生の[および]内にも現れる場合、関数の呼び出しごとに、対応する実際の引数の値は、指定された数以上の要素を持つ配列の最初の要素へのアクセスを提供します。サイズ式によって。

(C99、§6.7.5.3、¶7、強調が追加されました)

つまり、これはvolatileだけに限定されず、constrestrictも許可されます(Type qualifiers、§6.7.3¶1を参照)。

このハックのポイントは、本質的に、型修飾子パラメータにnotを配列の要素に)を追加し、宣言の配列構文を保持できるようにすることです。この構文がないと、ポインターとして書き出すことに強制されます(とにかく要約しますstaticケースを除く、これは同等のポインター構文を持っていません) 。

私の考えは、多次元配列の構文を少しだけ扱いにくくすることだと思う。引用6.7.5.3¶21:

void f(double (* restrict a)[5]);
void f(double a[restrict][5]);
void f(double a[restrict 3][5]);

はすべて同等ですが、2と3は、これが単なるポインタではなく配列であり、restrict修飾子を配置する場所を許可することを意図していることをわずかに伝えることができます。

また、上記のように、次のようなものを持つ方法はないようです

void f(double a[restrict static 3][5]);

(これは、「aの呼び出しでfに対応する引数が、5つのdoubleの少なくとも3つの配列の最初への非NULLポインターでなければならないことも指定する」、ibidem)ポインター構文。

それでも、この構文には近づかないでしょう。それは非常に不明瞭で、めったに使用されません(配列に型修飾子を追加する必要はないと思いますparameter-繰り返しますが、要素型ではなくパラメーター自体です。restrictが唯一のユースケースです理にかなっています)-C++に移植性がありません(ライブラリを作成する場合に一般的に関連します)。

14
Matteo Italia