Dにおける静的配列の動的配列

Dでは、静的配列(多次元含む)は全体が連続した領域として確保されたはず。それならa[4][ ]みたいなの(静的配列の動的配列)とか、b[4][3][ ]みたいなの(静的な多次元配列の動的配列)ってどう確保されるの?と思ったので以下のコードを書いて実験してみた。
OSはWindows XP SP2、Dコンパイラdmd Ver.1.0を使用。

import std.cstream;

int main(char[][] args)
{
	double[4][] a;
	a.length = 3;
	dout.writefln("a[4][]:");
	for (int i = 0; i < a.length; i++)
		dout.writefln("\t%d, %d, %d, %d",
					  cast(uint)&a[i][0] - cast(uint)a.ptr,
					  cast(uint)&a[i][1] - cast(uint)a.ptr,
					  cast(uint)&a[i][2] - cast(uint)a.ptr,
					  cast(uint)&a[i][3] - cast(uint)a.ptr);

	double[][] b;
	b.length = 3;
	for (int i = 0; i < b.length; i++) b[i].length = 4;
	dout.writefln("b[][]:");
	for (int i = 0; i < b.length; i++)
		dout.writefln("\t%d, %d, %d, %d",
					  cast(uint)&b[i][0] - cast(uint)b.ptr,
					  cast(uint)&b[i][1] - cast(uint)b.ptr,
					  cast(uint)&b[i][2] - cast(uint)b.ptr,
					  cast(uint)&b[i][3] - cast(uint)b.ptr);

	double[4][3][] c;
	c.length = 3;
	dout.writefln("c[4][3][]:");
	for (int i = 0; i < c.length; i++)
		for (int j = 0; j < c[i].length; j++)
			dout.writefln("\t%d, %d, %d, %d",
						  cast(uint)&c[i][j][0] - cast(uint)c.ptr,
						  cast(uint)&c[i][j][1] - cast(uint)c.ptr,
						  cast(uint)&c[i][j][2] - cast(uint)c.ptr,
						  cast(uint)&c[i][j][3] - cast(uint)c.ptr);

	double[4][][] d;
	d.length = 3;
	for (int i = 0; i < d.length; i++) d[i].length = 3;
	dout.writefln("d[4][][]:");
	for (int i = 0; i < d.length; i++)
		for (int j = 0; j < d[i].length; j++)
			dout.writefln("\t%d, %d, %d, %d",
						  cast(uint)&d[i][j][0] - cast(uint)d.ptr,
						  cast(uint)&d[i][j][1] - cast(uint)d.ptr,
						  cast(uint)&d[i][j][2] - cast(uint)d.ptr,
						  cast(uint)&d[i][j][3] - cast(uint)d.ptr);
	for (int i = 0; i < d.length; i++)
		for (int j = 0; j < d[i].length; j++)
			dout.writefln("\t%d, %d, %d, %d",
						  cast(uint)&d[i][j][0] - cast(uint)d[i].ptr,
						  cast(uint)&d[i][j][1] - cast(uint)d[i].ptr,
						  cast(uint)&d[i][j][2] - cast(uint)d[i].ptr,
						  cast(uint)&d[i][j][3] - cast(uint)d[i].ptr);

	return 0;
}

結果:

a[4]:
        0, 8, 16, 24
        32, 40, 48, 56
        64, 72, 80, 88
b:
        4294958816, 4294958824, 4294958832, 4294958840
        4294958752, 4294958760, 4294958768, 4294958776
        4294958688, 4294958696, 4294958704, 4294958712
c[4][3]:
        0, 8, 16, 24
        32, 40, 48, 56
        64, 72, 80, 88
        96, 104, 112, 120
        128, 136, 144, 152
        160, 168, 176, 184
        192, 200, 208, 216
        224, 232, 240, 248
        256, 264, 272, 280
d[4]:
        4294962880, 4294962888, 4294962896, 4294962904
        4294962912, 4294962920, 4294962928, 4294962936
        4294962944, 4294962952, 4294962960, 4294962968
        4294962752, 4294962760, 4294962768, 4294962776
        4294962784, 4294962792, 4294962800, 4294962808
        4294962816, 4294962824, 4294962832, 4294962840
        4294962624, 4294962632, 4294962640, 4294962648
        4294962656, 4294962664, 4294962672, 4294962680
        4294962688, 4294962696, 4294962704, 4294962712
        0, 8, 16, 24
        32, 40, 48, 56
        64, 72, 80, 88
        0, 8, 16, 24
        32, 40, 48, 56
        64, 72, 80, 88
        0, 8, 16, 24
        32, 40, 48, 56
        64, 72, 80, 88

というわけで、静的な配列(多次元含む)の動的配列では、全部の領域が連続して確保されるっぽい。でも、さらにその動的配列となると駄目。
うーん、確かめてみると当然の結果な気がする…何を疑問に思っていたんだろう。
(追記)何がしたかったかというと、DからCのライブラリに引数として多次元配列を渡すときにどうすればいいのかを知りたかったんだった。結論:

  • 完全に静的な多次元配列か、最上位の次元のみ動的な多次元配列なら渡しても問題ないと思われる。
  • 関数プロトタイプの引数の型はdouble[4]*のようにしといて、使うときは.ptrプロパティを与えてやれば、静的・動的の双方に対応できて良いと思われる。

以上。