casting pointers/arrays to multidimensional arrays

F

Francesco

Hi to all,

would any of you gentlemen please comment on the reinterpret_casts in
the code below?
Do you think they're ok or not? Any reference to the standard would be
greatly appreciated.

Thank in advance,
FB

//CODE
#include <iostream>
#include <iomanip>

typedef float ( * tMtx )[ 4 ];

void Fill( tMtx inMtx )
{
for( int c = 0; c < 16; ++c )
inMtx[ c / 4 ][ c % 4 ] = c;
}

void Print( tMtx inMtx )
{
std::cout << "n->" << inMtx << std::endl;
for( int c1 = 0; c1 < 4; ++c1 )
{
for( int c2 = 0; c2 < 4; ++c2 )
std::cout << std::setw( 5 ) << inMtx[ c1 ][ c2 ];
std::cout << std::endl;
}
std::cout << std::endl;
}

int main()
{
float mtx1[ 16 ] = { 0 };
float mtx2[ 4 ][ 4 ];
float * mtx3 = new float[ 16 ];
float * mtx4 = reinterpret_cast< float * >( new float[ 4 ][ 4 ] );

// are these casts OK?
Fill( reinterpret_cast< tMtx >( mtx1 ) );
Fill( mtx2 );
Fill( reinterpret_cast< tMtx >( mtx3 ) );
Fill( reinterpret_cast< tMtx >( mtx4 ) );

Print( reinterpret_cast< tMtx >( mtx1 ) );
Print( mtx2 );
Print( reinterpret_cast< tMtx >( mtx3 ) );
Print( reinterpret_cast< tMtx >( mtx4 ) );

delete[] mtx3;
delete[] mtx4;

std::cin.get();
}
//ENDCODE
 
J

James Kanze

would any of you gentlemen please comment on the
reinterpret_casts in the code below?
Do you think they're ok or not? Any reference to the standard
would be greatly appreciated.
//CODE
#include <iostream>
#include <iomanip>
typedef float ( * tMtx )[ 4 ];
void Fill( tMtx inMtx )
{
for( int c = 0; c < 16; ++c )
inMtx[ c / 4 ][ c % 4 ] = c;
}
void Print( tMtx inMtx )
{
std::cout << "n->" << inMtx << std::endl;
for( int c1 = 0; c1 < 4; ++c1 )
{
for( int c2 = 0; c2 < 4; ++c2 )
std::cout << std::setw( 5 ) << inMtx[ c1 ][ c2 ];
std::cout << std::endl;
}
std::cout << std::endl;
}
int main()
{
float mtx1[ 16 ] = { 0 };
float mtx2[ 4 ][ 4 ];
float * mtx3 = new float[ 16 ];
float * mtx4 = reinterpret_cast< float * >( new float[ 4 ][ 4 ] );
// are these casts OK?
Fill( reinterpret_cast< tMtx >( mtx1 ) );
Fill( mtx2 );
Fill( reinterpret_cast< tMtx >( mtx3 ) );
Fill( reinterpret_cast< tMtx >( mtx4 ) );
Print( reinterpret_cast< tMtx >( mtx1 ) );
Print( mtx2 );
Print( reinterpret_cast< tMtx >( mtx3 ) );
Print( reinterpret_cast< tMtx >( mtx4 ) );
delete[] mtx3;
delete[] mtx4;
std::cin.get();
}
//ENDCODE

They're reinterpret_cast. Formally, I think using the results
of them here is undefined behavior. If you're implementation
says it's OK, they should work. And in practice, most
implementations don't say anything, but they work anyway.

Of course, they're not something you'd want to see in production
code.
 
F

Francesco

 Francesco said:
Hi to all,
would any of you gentlemen please comment on the reinterpret_casts in
the code below?
Do you think they're ok or not? Any reference to the standard would be
greatly appreciated.
Thank in advance,
FB
//CODE
#include <iostream>
#include <iomanip>
typedef float ( * tMtx )[ 4 ];
void Fill( tMtx inMtx )
{
    for( int c = 0; c < 16; ++c )
        inMtx[ c / 4 ][ c % 4 ] = c;
}
void Print( tMtx inMtx )
{
    std::cout << "n->" << inMtx << std::endl;
    for( int c1 = 0; c1 < 4; ++c1 )
    {
        for( int c2 = 0; c2 < 4; ++c2 )
            std::cout << std::setw( 5 ) << inMtx[ c1 ][ c2 ];
        std::cout << std::endl;
    }
    std::cout << std::endl;
}
int main()
{
    float mtx1[ 16 ] = { 0 };
    float mtx2[ 4 ][ 4 ];
    float * mtx3 = new float[ 16 ];
    float * mtx4 = reinterpret_cast< float * >( new float[ 4 ][ 4 ] );
    // are these casts OK?
    Fill( reinterpret_cast< tMtx >( mtx1 ) );
    Fill( mtx2 );
    Fill( reinterpret_cast< tMtx >( mtx3 ) );
    Fill( reinterpret_cast< tMtx >( mtx4 ) );
    Print( reinterpret_cast< tMtx >( mtx1 ) );
    Print( mtx2 );
    Print( reinterpret_cast< tMtx >( mtx3 ) );
    Print( reinterpret_cast< tMtx >( mtx4 ) );
    delete[] mtx3;
    delete[] mtx4;
    std::cin.get();
}
//ENDCODE

It's doable, but I would do it differently:

// begin code
typedef float m16[16];
typedef float m44[4][4];

void Fill(m44& v) {
   for(int c = 0; c < 16; ++c)
      v[c / 4][c % 4] = c;

}  

void Fill(m16& v) {
   Fill(reinterpret_cast<m44&>(v));

}

void Print(const m44& v) {
   cout << "n->" << v << endl;
   for (int c1 = 0; c1 < 4; ++c1) {
      for (int c2 = 0; c2 < 4; ++c2)
         cout << setw(5) << v[c1][c2];
      cout << endl;
   }
   cout << endl;

}

void Print(const m16& v) {
   Print(reinterpret_cast<const m44&>(v));

}

int main()
{
   float mtx1[16] = { 0 };
   float mtx2[4][4];

   Fill(mtx1);
   Fill(mtx2);

   Print(mtx1);
   Print(mtx2);

   cin.get();}

// end code

Even if you are stuck with the Fill and Print you have, I would still
wrap the casts in functions that take the appropriate types. That way
you don't have (1) reinterpret_cast all over your code and (2) it is
less likely that someone will reinterpret_cast the wrong sort of
variable.- Nascondi testo citato

- Mostra testo citato -

Thanks for the answers and hints.
I was just interested in knowing if casting from a "flat" pointer to a
multidimensional array (or backwards) is formally defined, undefined
behavior or implementation defined.
For the record: I've found an old thread in comp.lang.c where people
had mixed feelings about the issue and it seems that both standards (C
and C++) are not that clear on the subject.

http://groups.google.it/group/comp.lang.c/browse_thread/thread/367141614adee786/

Summary: the memory layout of something like float [16] should be the
same as float[4][4] but since the implementation might "magically" do
different bounds checking (??), the following code might cause trouble
on some (??) implementations:

//CODE
#include <cassert>

int main()
{
float array44[4][4];
// DEFINED, UB OR IMPLEM DEFINED ?
float * ptr = reinterpret_cast<float*>( array44 );
ptr[6] = 123.123;
assert( (void*)&array44[1][2] == (void*)&ptr[1*4+2] );

// OPPOSITE CASE
float array16[16] = {0};
// DEFINED, UB OR IMPLEM DEFINED ?
float (*ptr44)[4] = reinterpret_cast<float(*)[4]>( array16 );
ptr44[1][2] = 123.123;
assert( (void*)&array16[1*4+2] == (void*)&ptr44[1][2] );
}

//ENDCODE

Again for the record: I'm interested in using the flat to
multidimensional cast because I'd prefer to use the [][][] in some
functions that have as input flat arrays (created by somebody else)...
Thanks a lot again,
Francesco
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top