Rocksolid Light

Welcome to RetroBBS

mail  files  register  newsreader  groups  login

Message-ID:  

"Time is money and money can't buy you love and I love your outfit" -- T.H.U.N.D.E.R. #1


devel / comp.lang.c++ / Re: Problem with calling C++ from Fortran

Re: Problem with calling C++ from Fortran

<87a5trplua.fsf@bsb.me.uk>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=1468&group=comp.lang.c%2B%2B#1468

  copy link   Newsgroups: comp.lang.c++
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: ben.usenet@bsb.me.uk (Ben Bacarisse)
Newsgroups: comp.lang.c++
Subject: Re: Problem with calling C++ from Fortran
Date: Tue, 12 Sep 2023 14:22:53 +0100
Organization: A noiseless patient Spider
Lines: 228
Message-ID: <87a5trplua.fsf@bsb.me.uk>
References: <udhbs9$e5d$1@dont-email.me> <udhcaj$j8l$1@dont-email.me>
<udkdu9$itm4$1@dont-email.me> <87o7iajh8b.fsf@bsb.me.uk>
<udmvg7$11r4u$1@dont-email.me> <87cyyoqoka.fsf@bsb.me.uk>
<2ccb965a-8d31-48af-97ad-2d96daa4862dn@googlegroups.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
Injection-Info: dont-email.me; posting-host="0b3d05af22d1f5f0f239039facdde43d";
logging-data="1662275"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19O2udUvXgiZw89/9ibHKJPjdjEk5bY9lo="
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.2 (gnu/linux)
Cancel-Lock: sha1:KGc9VGkdjPEd1P8UbWiuN7WsTWg=
sha1:TrqZUu72ukYoPukjyVDJLGtKcLY=
X-BSB-Auth: 1.4ac430060a7e3c2358b2.20230912142253BST.87a5trplua.fsf@bsb.me.uk
 by: Ben Bacarisse - Tue, 12 Sep 2023 13:22 UTC

Michael S <already5chosen@yahoo.com> writes:

> On Tuesday, September 12, 2023 at 2:26:49 AM UTC+3, Ben Bacarisse wrote:
>> db <dieterh...@gmail.com> writes:
>>
>> > On 10.09.2023 15.22, Ben Bacarisse wrote:
>> >> db <dieterh...@gmail.com> writes:
>> >>
>> >>> On 09.09.2023 11.02, Mut...@dastardlyhq.com wrote:
>> >>>> On Sat, 9 Sep 2023 10:54:33 +0200
>> >>>> db <dieterh...@gmail.com> wrote:
>> >>>>> but now it says that C-double doesn't exist.
>> >>>>>
>> >>>>> Any ideas?
>> >>>> C++ mangles function names so that the name you give the function isn't
>> >>>> the
>> >>>> name the dynamic loader sees in the binary. You need to put this around whatever
>> >>>> function you want to call from Fortran so it has C style linkage which means
>> >>>> the name remains the same:
>> >>>> extern "C" {
>> >>>> void calledFromFortran()
>> >>>> {
>> >>>> :
>> >>>> }
>> >>>> }
>> >>>>
>> >>> Where should this go in the code? I added it at the end as is,
>> >>> and now I get this:
>> >>>
>> >>> ~/ownlib90/tests> ./jbandtest
>> >>> jband.cpp:88:1: error: expected initializer before 'extern'
>> >>> 88 | extern "C" {
>> >>> | ^~~~~~
>> >>> jband.cpp:96:1: error: expected unqualified-id before '{' token
>> >>> 96 | {
>> >>> | ^
>> >>> jband.cpp: In function 'void calledFromFortran()':
>> >>> jband.cpp:350:9: error: expected primary-expression before ':' token
>> >>> 350 | :
>> >>> ...
>> >> You are giving people very little to go on. There's an unknown command
>> >> (./jbandtest) the gives some errors where only one line of code can be
>> >> seen.
>> >> Can you produce a cut-down version to the program that shows the same
>> >> error -- mimimal example of the C++ and of the Fortran that should
>> >> calls it but which fails? That would mean you could post the code.
>> >> If that is not possible, can you link to the source so those who know
>> >> both C++ and Fortran can take a proper look?
>> >
>> > I put the C++ function here: www.dieterbritz.dk/jband.cpp
>> > After getting errors about the extern lines, whch I had
>> > added at the end, I shifted it to near the start:
>> >
>> > #include <iostream>
>> > #include <fstream>
>> > #include <iomanip>
>> > #include "math.h"
>> >
>> > using namespace std;
>> >
>> > extern "C" {
>> >
>> > void calledFromFortran()
>> > {
>> > :
>> > }
>> >
>> > }
>> Remove them all. You have two options. One: correct the C++. To do
>> this put this, and only this,
>>
>> extern "C" {
>> const long double iband(const long double tbar);
>> }
>>
>> just after the #include lines. This is perfect (the first const is a
>> meaningless word here and the compiler may warn you about that) but it
>> will do.
>>
>> Next replace
>>
>> #include "math.h"
>>
>> with
>>
>> #include <math.h>
>>
>> I'd also remove the two unnecessary #include lines (for iomanip and
>> fstream). All of these are "tidying up". Only the extern "C" part I
>> gave corrects an actual mistake.
>>
>> The second option is the turn the code in C which links directly with
>> Fortran. The only C++ used by the code is one "cout << " line (not a
>> good way to report an error, but that's not important right now) and a
>> setting for pi that is not a compile-time constant (4*atanl(1)) written
>> in a more fussy way.
>>
>> To convert to C, copy the file to jband.c (rather than .cpp) and replce
>> the declaration for pi. Given the code is littered with explicit 21
>> digits decimals (a little more than the precision of C's usualy long
>> double type) I would just write
>>
>> static const long double pi = 3.14159265358979323846L;
>>
>> Now replace the cout line with
>>
>> fputs("\nError in stredges::iband(): tbar must be > 0", stderr);
>>
>> This writes the message to the error stream and put only these two
>> include lines at the top:
>>
>> #include <math.h>
>> #include <stdio.h>
>>
>> Now the file is C code.
>>
>> Frankly, this is the way I'd go, since linking C is just that bit
>> simpler than linking C++. But if the code is going to become fully
>> fledged (and complex) C++, obviously use my first option.
>> > I still get errors pertaining to these lines. But after adding
>> > the -c to the two compilation lines in the script, these are
>> > now the only errors. I think I am getting closer. The errors
>> > are now
>> Yes, you must compile it like this:
>>
>> g++ -c jband.cpp (for C++ code)
>> gcc -c jband.c (for C code)
>>
>> You don't need any -o but you could add in lots of warnings like
>>
>> gcc -Wall -Wextra -c jband.c
>> > jband.cpp: In function 'void calledFromFortran()':
>> > jband.cpp:12:9: error: expected primary-expression before ':' token
>> > 12 | :
>> > | ^
>> > jband.cpp: At global scope:
>> > jband.cpp:96:1: error: expected initializer before 'extern'
>> > 96 | extern "C" {
>> > | ^~~~~~
>> > jband.cpp:104:1: error: expected unqualified-id before '{' token
>> > 104 | {
>> > | ^
>> > jbandtest.f90:28:14:
>> >
>> > 28 | FORTJBAND = JBAND (tbar)
>> > | 1
>> > Error: Type mismatch in argument 'tbar' at (1); passed REAL(16) to REAL(10)
>> >
>> > The last error will go away together with the others.
>> Michael S has given you one way to go for that. My comments were going
>> to be more general. You have several ways of specifying the types, and
>> I could not tell if you really wanted all of them. In general, I would
>> define the Fortran types from the C ones (since those are the types you
>> need for the call and return) and leave it at that.
>>
>> But the big one is that the Fortran code seems to think the function is
>> called jband, when in fact it's called iband.
>>
>> I went for this:
>>
>> module STUFF
>> use iso_c_binding
>> integer, parameter :: qud=real(c_long_double)
>> end module STUFF
>> program JBAND_TEST
>> use STUFF; implicit none
>> real(qud) :: tbar, curr, FORTJBAND
>> do
>> read *, tbar
>> if (tbar < 0) exit
>> curr = FORTJBAND (tbar)
>> print '(" curr =", f10.4)', curr
>> enddo
>> end program JBAND_TEST
>>
>> function FORTJBAND (tbar)
>> use STUFF; implicit none
>> interface
>> function IBAND (tbar) bind(c)
>> use STUFF
>> real(qud), VALUE :: tbar
>> real(qud) :: IBAND
>> end function iband
>> end interface
>
> I think, you are taking chances here. Even if it happens to work
> on x86-64 Linux, it can fail on some other target where calling
> conventions for long double return value in 'C' differ from those
> of Fortran. The method shown in one of my previous posts
> appear more robust:
>
> interface
> real(c_long_double) function IBAND (tbar) bind(c)
> import c_long_double
> real(c_long_double), value :: tbar
> end function IBAND

I think I see -- keep the C-related types in the smallest interface? I
didn't study your example, but the OP renamed the C function and gave
the resulting Fortran function a native Fortran type. Is that what you
advise?

The OP should have taken your Fortran and applied my C++ edits. Maybe
they took my Fortran and it did not work on Windows. That would be a
shame.

>> BTW, you said the C++ was written by a C++ expert. I don't think it
>> was!
>
> With no relationships to C, C++ or Fortran, I don't like the way they
> evaluate their polynomials from numerical perspective . But I assume
> that algorithm was copied 'as is' from 40 y.o. book so it's not a
> fault of C++ programmer.

I was just remarking on the C++ itself which has some 'non-expert'
attributes.

> Despite my disliking, their method is good enough to achieve their modest
> specified goal for relative accuracy: of 14-15 significant digits.
> With smarter method the same or better accuracy can be achieved using
> standard 'double" arithmetic (IEEE-754 binary64) thus making the routine
> portable to platforms that have no support for extended precision
> math.

Interesting. I don't know the function being evaluated at all.

--
Ben.

SubjectRepliesAuthor
o Problem with calling C++ from Fortran

By: db on Sat, 9 Sep 2023

31db
server_pubkey.txt

rocksolid light 0.9.81
clearnet tor