C言語での static キーワード付き配列パラメータ宣言
[
〜]
の間に指定されるstatic
In addition to optional type qualifiers and the keyword
static
, the[
and]
may delimit an expression or*
. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero. The element type shall not be an incomplete or function type. The optional type qualifiers and the keywordstatic
shall appear only in a declaration of a function parameter with an array type, and then only in the outermost array type derivation.
C99 でも 6.7.5.2 の 1 にかかれているが完全に同一の文となっている。
- 任意の型修飾子とキーワード
static
に加えて、式または*
を[
〜]
の中に含める(MAY)。 - もし
[
〜]
が式(配列の長さを指定)を含むのならば、その式は整数(integer)型を持つ(SHALL)。 - もしその式が定数ならば、その式は0より大きな値を持つ(SHALL)。
- 要素の型は不完全型または関数型であってはならない(SHALL NOT)。(訳注:要素の型は関数ポインタは可)
- 任意の型修飾子とキーワード
static
は、配列型の関数パラメータ宣言の中のみに記述され、 最も外側のarray type derivationのみに記述される(SHALL)。
ここで関数引数宣言の配列に限ってのみ[
〜]
の中に修飾子を書いて良いと書かれていて、
たとえば restrict
キーワードがこれに該当する。
ここにて型修飾子とは別枠で static
を書けると言っている。
詳細は関数の方に書いていて、下記のとおりである:
A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the
[
and]
of the array type derivation. If the keywordstatic
also appears within the[
and]
of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
こちらも C99 でも 6.7.5.3 の 7 にかかれているが完全に同一の文となっている。
- typeの配列としてパラメータ宣言は、typeへのqualified pointerに調整される(SHALL)。
- ここで型修飾子は(もしあれば) array type derivation の
[
〜]
の間に指定される。 - もしキーワード
static
が array type derivation の[
〜]
の間に指定されるならば、 それぞれの関数呼び出しに対して、 対応する実際の引数の値は配列の最初の要素についてサイズ指定の数以上参照できなければならない(SHALL)。
要するに下記のとおりということだ:
課題コード EXAMPLE 4
課題コードとして、規格の下記コードスニペットで考える
(gcc
でコンパイルするときは--std=c11
指定すること)。
まずは static
キーワードのことはなしで考察する。
EXAMPLE 4 The following prototype has a variably modified parameter.
ところで、このすぐ下にこんな例がある:
EXAMPLE 5 The following are all compatible function prototype declarators.
as are:
(Note that the last declaration also specifies that the argument corresponding to
a
in any call tof
must be a non-null pointer to the first of at least three arrays of 5 doubles, which the others do not.)
よって、addscalar
のプロトタイプ宣言は下記のようにも変更可能。
ところで下記のようにすると、a
は不完全型ということでコンパイルが通らない。
少なくともふたつ目の[
〜]
の間には数字を入れなくてはいけない。
単純に定数値を入れるとすると例えば下記のような感じになると思われる。 (C言語規格解釈のためのコードであって使い物にならないコードスニペットになってしまっているが。)
ここで308をn*m+300
に可変長配列化したものがExample 4のコードということみたいだ。
そもそもひとつ目は単なるqualified pointerに過ぎないのだから
と書けば、”a
is a pointer to a VLA …” であって “a
is a VLA …” ではないことが明瞭にわかる。
EXAMPLE 4 の [
〜]
の間にstatic
を
まず、本節のタイトル通りのことを何も考えずにやると
というコードになるが、コンパイルエラーになる。
前節で書いたとおり n*m+300
は(可変長)配列長そのものだからである。
多次元配列の一番左の[
〜]
以外は(可変長)配列の長さを指定しなければならないので、
規格としては最初に挙げたもののonly in the outermost array type derivation.に
あるように、[
〜]
の間に static
を入れるとしても一番左の[
〜]
だけである。
さて、一番左の[
〜]
における static
のない配列長の指定は、
特に意味のないものとして知られている。
例えば、下記コード中の sizeof()
はすべて同じ値を返す。
ここで例え a[static n][10]
としても配列長がn
以上としか意味しない。
よって、下記コード中の sizeof()
はやはりすべて同じ値を返す。
であるならば [static n]
が意味がありそうなのは、
呼び出し時の範囲確認ぐらいである。
試しに下記のようなコードにしてみた。
このとき、明らかに addscalar()
の呼び出し引数の配列サイズはオーバーしているので、
なんとかしてほしいものであったが、LLVM Clang も GCC も何も警告はなかった。
もうしばらく[static n]
は何も意味のないので使わない時期が続きそうだ。
参考文献
- WG14/N1256 Final version of the C99 standard with corrigenda TC1, TC2, and TC3 included, formatted as a draft, 7 Sep 2007.
- WG14/N1570 Commitee Draft ISO/IEC 9899:2011 (C11), 12 Apr 2011.
- 本の虫: 最近のC言語の配列, 12 Nov 2014.