web-dev-qa-db-ja.com

固定サイズの多次元配列に単純なポインターをキャストするにはどうすればよいですか?

浮動小数点配列へのポインターを取る関数があります。他の条件に基づいて、ポインタが実際に2x2 OR 3x3行列を指していることを知っています(実際、メモリは最初、フロートM [2] [2]などとして割り当てられていました)。重要なことは、関数の引数としてではなく、関数本体でこの決定を行いたいということです。

void calcMatrix( int face, float * matrixReturnAsArray )
{
    // Here, I would much rather work in natural matrix notation
    if( is2x2 )
    {
        // ### cast matrixReturnAsArray to somethingAsMatrix[2][2]
        somethingAsMatrix[0][1] = 2.002;
        // etc..
    }
    else if(is3x3)
    { //etc...
    }

}

この問題により適切に対処するために、テンプレートやその他の手法を使用できることを認識しています。私の質問は、###コメントでそのようなキャストを作成する方法についてです。 C++での作業。

22
NoahR
float (*somethingAsMatrix)[2] = (float (*)[2]) matrixReturnAsArray;
26
ecatmur

float *は、floatの配列の最初の要素を指す可能性があり、その配列タイプにreinterpret_castableする必要があります。そして、そのキャストの結果はfloat [][]の最初の要素を指す可能性があるため、その型にreinterpret_castableにする必要があります。あなたはそのようなキャストを構成し、直接行うことができるはずです

float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(matrixReturnAsArray);

タイプfloat **の引数は同じではないため、この方法で使用しないでください。

未定義の動作を回避するために、ポインタは実際の多次元配列から発生する必要があり、float*を直接使用する場合は、多次元行列の最初の行以外にはアクセスできません。

void foo(float *f) {
    f[3] = 10.;

    float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(f);
    arr[1][1] = 10.;
}

void main() {
    float a[2][2];
    foo(&a[0][0]); // f[3] = 10.; is undefined behavior, arr[1][1] = 10. is well defined

    float b[4];
    foo(&b[0]); // f[3] = 10.; is well-defined behavior, arr[1][1] = 10. is undefined
}

float arr[2][2];を指定しても、私が判断できる限り、&arr[0][1] + 1&arr[1][0]と同じであることは保証されません。したがって、f[i*width + j]を実行することで、1次元配列を多次元配列として使用できますが、多次元配列を1次元配列のように扱うことはできません。

誤って間違ったものを渡したり、間違ったreinterpret_castを実行したりするのではなく、C++のコンパイル時のタイプセーフを使用することをお勧めします。 raw配列を使用して型保証を取得するには、必要なraw配列型への参照を使用する必要があります。

void foo(float (&f)[2][2]) {}
void foo(float (&f)[3][3]) {}

値で配列を渡したい場合は、生の配列を使用できません。代わりにstd :: arrayのようなものを使用する必要があります。

void foo(std::array<std::array<float,2>,2> f) {}
void foo(std::array<std::array<float,3>,3> f) {}
5
bames53

Typedefの賢明な使用により、この種のキャストは常によりクリーンで扱いやすくなります。

typedef float Matrix_t[2][2];

Matrix_t* someThingAsMatrix = (Matrix_t*) matrixReturnAsArray;

ただし、これがC++でCではない場合は、行列クラスを作成する必要があります。 (あるいは、もっと良いのは、オープンソースのものを探してください。)

1
Gort the Robot