Call 2d std::vector array from C++ to Fortran 90 error-Collection of common programming errors
I am trying to call the following C++ function from Fortran 90.
//Filename ctest.cpp
#include
#include
extern "C"
{
extern struct{
std::vector< std::vector > a;
std::vector< std::vector > b;
std::vector< std::vector > c;
}abc_;
}
int myfunc_(int y,int z)
{
std::vector< std::vector > u(y,std::vector(z,2.0));
std::vector< std::vector > v(y,std::vector(z,4.0));
std::vector< std::vector > w(y,std::vector(z,6.0));
abc_.a = u;
abc_.b = v;
abc_.c = w;
return(1);
}
The corresponding fortran code is ! File fortest.f90 ! Fortran test code to interface with C++ code ! return struct from C++
program fortest
implicit none
common/abc/ a,b,c
double precision,dimension(10,10) :: a
double precision,dimension(10,10) :: b
double precision,dimension(10,10) :: c
integer y,z
y = 10
z = 10
call myfunc(y,z)
write(*,*) a,b,c
stop
end
Both codes compile without any problems individually. However, when I compile the 2 together to interface them, with
gfortran -o test fortest.o ctest.o
I get a really huge error message. I suspect the problem is with Fortran not recognizing C++ 2d std::vector. But I am enclosing the full message here in case anyone wants to have a look.
user@userpc$ gfortran -o test fortest.o ctest.o
fortest.o: In function `MAIN__':
fortest.f90:(.text+0x2d): undefined reference to `myfunc_'
ctest.o: In function `__static_initialization_and_destruction_0(int, int)':
ctest.cpp:(.text+0x379): undefined reference to `std::ios_base::Init::Init()'
ctest.cpp:(.text+0x37e): undefined reference to `std::ios_base::Init::~Init()'
ctest.o: In function `std::vector* std::vector::_M_allocate_and_copy(unsigned long, __gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator)':
ctest.cpp:(.text._ZNSt6vectorIS_IdSaIdEESaIS1_EE20_M_allocate_and_copyIN9__gnu_cxx17__normal_iteratorIPKS1_S3_EEEEPS1_mT_SB_[std::vector* std::vector::_M_allocate_and_copy(unsigned long, __gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator)]+0x62): undefined reference to `__cxa_end_catch'
ctest.cpp:(.text._ZNSt6vectorIS_IdSaIdEESaIS1_EE20_M_allocate_and_copyIN9__gnu_cxx17__normal_iteratorIPKS1_S3_EEEEPS1_mT_SB_[std::vector* std::vector::_M_allocate_and_copy(unsigned long, __gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator)]+0x75): undefined reference to `__cxa_begin_catch'
ctest.cpp:(.text._ZNSt6vectorIS_IdSaIdEESaIS1_EE20_M_allocate_and_copyIN9__gnu_cxx17__normal_iteratorIPKS1_S3_EEEEPS1_mT_SB_[std::vector* std::vector::_M_allocate_and_copy(unsigned long, __gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator)]+0x91): undefined reference to `__cxa_rethrow'
ctest.o: In function `__gnu_cxx::new_allocator::deallocate(std::vector*, unsigned long)':
ctest.cpp:(.text._ZN9__gnu_cxx13new_allocatorISt6vectorIdSaIdEEE10deallocateEPS3_m[__gnu_cxx::new_allocator::deallocate(std::vector*, unsigned long)]+0x1c): undefined reference to `operator delete(void*)'
ctest.o: In function `__gnu_cxx::new_allocator::allocate(unsigned long, void const*)':
ctest.cpp:(.text._ZN9__gnu_cxx13new_allocatorIdE8allocateEmPKv[__gnu_cxx::new_allocator::allocate(unsigned long, void const*)]+0x2c): undefined reference to `std::__throw_bad_alloc()'
ctest.cpp:(.text._ZN9__gnu_cxx13new_allocatorIdE8allocateEmPKv[__gnu_cxx::new_allocator::allocate(unsigned long, void const*)]+0x3c): undefined reference to `operator new(unsigned long)'
ctest.o: In function `__gnu_cxx::new_allocator::deallocate(double*, unsigned long)':
ctest.cpp:(.text._ZN9__gnu_cxx13new_allocatorIdE10deallocateEPdm[__gnu_cxx::new_allocator::deallocate(double*, unsigned long)]+0x1c): undefined reference to `operator delete(void*)'
ctest.o: In function `__gnu_cxx::new_allocator::allocate(unsigned long, void const*)':
ctest.cpp:(.text._ZN9__gnu_cxx13new_allocatorISt6vectorIdSaIdEEE8allocateEmPKv[__gnu_cxx::new_allocator::allocate(unsigned long, void const*)]+0x2c): undefined reference to `std::__throw_bad_alloc()'
ctest.cpp:(.text._ZN9__gnu_cxx13new_allocatorISt6vectorIdSaIdEEE8allocateEmPKv[__gnu_cxx::new_allocator::allocate(unsigned long, void const*)]+0x45): undefined reference to `operator new(unsigned long)'
ctest.o: In function `std::vector* std::__uninitialized_copy::__uninit_copy(std::vector*, std::vector*, std::vector*)':
ctest.cpp:(.text._ZNSt20__uninitialized_copyILb0EE13__uninit_copyIPSt6vectorIdSaIdEES5_EET0_T_S7_S6_[std::vector* std::__uninitialized_copy::__uninit_copy(std::vector*, std::vector*, std::vector*)]+0x62): undefined reference to `__cxa_end_catch'
ctest.cpp:(.text._ZNSt20__uninitialized_copyILb0EE13__uninit_copyIPSt6vectorIdSaIdEES5_EET0_T_S7_S6_[std::vector* std::__uninitialized_copy::__uninit_copy(std::vector*, std::vector*, std::vector*)]+0x75): undefined reference to `__cxa_begin_catch'
ctest.cpp:(.text._ZNSt20__uninitialized_copyILb0EE13__uninit_copyIPSt6vectorIdSaIdEES5_EET0_T_S7_S6_[std::vector* std::__uninitialized_copy::__uninit_copy(std::vector*, std::vector*, std::vector*)]+0x8d): undefined reference to `__cxa_rethrow'
ctest.o: In function `void std::__uninitialized_fill_n::__uninit_fill_n(std::vector*, unsigned long, std::vector const&)':
ctest.cpp:(.text._ZNSt22__uninitialized_fill_nILb0EE15__uninit_fill_nIPSt6vectorIdSaIdEEmS4_EEvT_T0_RKT1_[void std::__uninitialized_fill_n::__uninit_fill_n(std::vector*, unsigned long, std::vector const&)]+0x56): undefined reference to `__cxa_end_catch'
ctest.cpp:(.text._ZNSt22__uninitialized_fill_nILb0EE15__uninit_fill_nIPSt6vectorIdSaIdEEmS4_EEvT_T0_RKT1_[void std::__uninitialized_fill_n::__uninit_fill_n(std::vector*, unsigned long, std::vector const&)]+0x69): undefined reference to `__cxa_begin_catch'
ctest.cpp:(.text._ZNSt22__uninitialized_fill_nILb0EE15__uninit_fill_nIPSt6vectorIdSaIdEEmS4_EEvT_T0_RKT1_[void std::__uninitialized_fill_n::__uninit_fill_n(std::vector*, unsigned long, std::vector const&)]+0x81): undefined reference to `__cxa_rethrow'
ctest.o: In function `std::vector* std::__uninitialized_copy::__uninit_copy(__gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator, std::vector*)':
ctest.cpp:(.text._ZNSt20__uninitialized_copyILb0EE13__uninit_copyIN9__gnu_cxx17__normal_iteratorIPKSt6vectorIdSaIdEES4_IS6_SaIS6_EEEEPS6_EET0_T_SE_SD_[std::vector* std::__uninitialized_copy::__uninit_copy(__gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator, std::vector*)]+0x7c): undefined reference to `__cxa_end_catch'
ctest.cpp:(.text._ZNSt20__uninitialized_copyILb0EE13__uninit_copyIN9__gnu_cxx17__normal_iteratorIPKSt6vectorIdSaIdEES4_IS6_SaIS6_EEEEPS6_EET0_T_SE_SD_[std::vector* std::__uninitialized_copy::__uninit_copy(__gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator, std::vector*)]+0x8f): undefined reference to `__cxa_begin_catch'
ctest.cpp:(.text._ZNSt20__uninitialized_copyILb0EE13__uninit_copyIN9__gnu_cxx17__normal_iteratorIPKSt6vectorIdSaIdEES4_IS6_SaIS6_EEEEPS6_EET0_T_SE_SD_[std::vector* std::__uninitialized_copy::__uninit_copy(__gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator, std::vector*)]+0xa7): undefined reference to `__cxa_rethrow'
ctest.o: In function `double* std::vector::_M_allocate_and_copy(unsigned long, __gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator)':
ctest.cpp:(.text._ZNSt6vectorIdSaIdEE20_M_allocate_and_copyIN9__gnu_cxx17__normal_iteratorIPKdS1_EEEEPdmT_S9_[double* std::vector::_M_allocate_and_copy(unsigned long, __gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator)]+0x62): undefined reference to `__cxa_end_catch'
ctest.cpp:(.text._ZNSt6vectorIdSaIdEE20_M_allocate_and_copyIN9__gnu_cxx17__normal_iteratorIPKdS1_EEEEPdmT_S9_[double* std::vector::_M_allocate_and_copy(unsigned long, __gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator)]+0x75): undefined reference to `__cxa_begin_catch'
ctest.cpp:(.text._ZNSt6vectorIdSaIdEE20_M_allocate_and_copyIN9__gnu_cxx17__normal_iteratorIPKdS1_EEEEPdmT_S9_[double* std::vector::_M_allocate_and_copy(unsigned long, __gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator)]+0x91): undefined reference to `__cxa_rethrow'
ctest.o:(.eh_frame+0x6b): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
Any idea whats wrong…. in general terms how do I call multidimensional std::vectors from C++ in fortran? This will be of great use to people doing computational sciences.
-
std::vector
is an object that can be expected to have various data members such as capacity, pointer-to-start-of-data, pointer-to-end etc.. The exact layout is not specified by the Standard – implementations may vary. The data is not stored directly in thevector
– normally the pointer-to-start-of-data addresses heap-allocated memory. Therefore, you can’t just point a fortran array at thevector
object, as it will expect double data to be contiguously in memory from that address. You can’t even use the.data()
member to get the address where the pointer points, as in your case that’s anothervector
and has the same problem. Put another way, your data just isn’t contiguous in memory so won’t correspond to the memory layout for a 2-dimensional array.You could try copying the data into a packed two-dimensional array: if you know the dimensions will always be 10×10, then you can use a stack allocated area such as
double data[10][10]
, otherwise you candouble* p = new double[100]
and put the logical value for[x][y]
into element[x*10+y]
. I’m guessing that’s what your fortran implementation will expect but don’t know for sure. It could be that it will expect contiguous data but packs it using[x+10*y]
, or it’s even possible that it might introduce some other padding. It’s worth checking with your fortran documentation. If all else fails (or you just think it’s fun) you should be able to work it out by putting data into the fortran array and looking at the memory in a debugger to work out the layout.
Originally posted 2013-11-09 22:50:02.