views:

204

answers:

4

I'm trying to get some FORTRAN code to call a couple c++ functions that I wrote (c_tabs_ being one of them). Linking and everything works just fine, as long as I'm calling functions that don't belong to a class.

My problem is that the functions I want the FORTRAN code to call belong to a class. I looked at the symbol table using nm and the function name is something ugly like this:

00000000 T _ZN9Interface7c_tabs_Ev

FORTRAN won't allow me to call a function by that name, because of the underscore at the beginning, so I'm at a loss.

The symbol for c_tabs when it's not in a class is quite simple, and FORTRAN has no problems with it:

00000030 T c_tabs_

Any suggestions? Thanks in advance.

+4  A: 

You will need to create a c-style interface and "extern" it. C++ mangles method names (and overloaded functions) for linking. It's notoriously difficult to link C++ with anything except C++. There are "ways" but I'd highly suggest that you simply export a C interface and use the standard facilities available in Fortran.

Pestilence
+6  A: 

The name has been mangled, which is what the C++ compiler does to functions to allow things like function overloading and type-safe linkage. Frankly, you are extremely unlikely to be able to call member functions from FORTRAN (because FORTRAN cannot create C++ class instances, among other reasons) - you should express your interface in terms of a C API, which will be callable from just about anywhere.

anon
+3  A: 

You have to create extern "C" wrappers to handle all the details of FORTRAN calling C++, name mangling being the most obvious.

class foo {
public:
    int a_method (int x);
}

extern "C" int foo_a (foo * pfoo, int * px) {
    if (NULL == pfoo)
        return 0;
    else
        return pfoo->a_method (*px);
}

Notice that FORTRAN compilers pass all arguments by reference, never by value. (Although I'm told this is not strictly speaking part of the FORTRAN standard.)

Die in Sente
Which kind of makes you wonder where he is going to get the foo pointer from?
anon
I would make pfoo a void* and you will need a method to create foo objects 'extern "C" void* foo_create()'!
Martin York
How would I get a pointer to a pre-existing foo object?
Dane Larsen
+3  A: 

If you make the C++ routine have a C-style interface (as described already), then you can use the ISO C Binding feature of Fortran 2003 to call it. With the ISO C Binding, you can specify the name of the routine and (within limits) the C-types and calling conventions (reference, by value) of the arguments and function return. This method works well and has the advantage of being a standard, and therefore compiler and platform dependent, unlike the old methods of calling C from Fortran. The ISO C Binding is supported by many Fortran 95 compilers, such as gfortran >= 4.3.

M. S. B.
+1 for suggesting use of ISO C Binding which makes very straightforward and robust what used to be rather complicated and fragile.
High Performance Mark
Perfect! This is exactly what I was looking for. I was playing around with creating a C interface like Die in Sente suggested in his reply, but it's a pain. Thanks a ton.
Dane Larsen