[Ipopt] string array to ipopt-fortran

Jonathan Hogg jonathan.hogg at stfc.ac.uk
Mon Mar 26 09:05:10 EDT 2012


Fabian,

Fortran character variables normally have a defined length, so arrays 
can be handled via a simple byte offset. They also carry their length 
around with them in some fashion. This makes character(len=*) arrays a 
bit of a funny beast, and probably compiler dependent how they are 
implemented. I doubt you can pass anything from C that matches the type 
without using the latest draft TR from the Fortran standards committee 
(though I think this is implemented in this month's release of gcc).

C-style strings (different from C++-style strings defined using the C++ 
'string' class) as you use here are pointers, so char ** is an array of 
pointers to pointers.

You need to unwrap the C-style string array to a Fortran one. Something 
like the following code might work (I've not run it past a compiler, so 
there may be mistakes)

subroutine foo (nstr, maxlen, c_str_array) bind(C)
    use iso_c_binding
    integer(C_INT), value :: nstr, maxlen
    type(C_PTR), dimension(nstr) :: c_str_array

    integer :: i, j
    character(kind=C_CHAR, len=1), dimension(:), pointer :: str_ptr
    character(kind=C_CHAR, len=maxlen), dimension(nstr) :: f_str_array

    do i=1, nstr
        call C_F_POINTER(c_str_array(i), str_ptr, shape=(/ maxlen /) )
        do j=1,maxlen
           f_str_array(i:i) = str_ptr(i)
        end do
     end do

     ! Use f_str_array(:) to do useful things...

end subroutine foo

Jonathan.

On 26/03/12 11:24, Fabian Wein wrote:
> Hi Jonathan,
>
> thanks for your reply.
>
> My plan is to pass from C++ strings and length's and convert it.
>
> This is my current test:
>
> C-Header:...
>          const int* ipopt_nargs,        // ON INPUT (I): Number of 
> parameters passed to IPOPT23
>          double* ipopt_args,            // ON INPUT (I): Values passed 
> to IPOPT23
>          char**  ipopt_cargs_c,         // ON INPUT (I): name of 
> parameters passed to IPOPT23
>          int*    ipopt_cargs_l);          // ON INPUT (I): length's of 
> the parameter names
>
>
>       SUBROUTINE ....
>       INTEGER          IPOPT_NARGS,IPOPT_CARGS_L(*),IPOPT_TMP
>       DOUBLE PRECISION IPOPT_ARGS(*)
>       CHARACTER*(*)    IPOPT_CARGS_C(*)
>       CHARACTER*256    IPOPT_CARGS(50), IPOPT_TMP_STR
>
> C     We need to transfer the ipopt subsolver options from C which are
> C     an array of strings.
>       DO 1220 IPOPT_TMP = 1, IPOPT_NARGS
>          IPOPT_TMP_STR(1:IPOPT_CARGS_L(IPOPT_TMP)) =
>      +                IPOPT_CARGS_C(IPOPT_TMP)
>          IPOPT_CARGS(1) = IPOPT_TMP_STR;
>          WRITE(*, *) 'param/leng/str:', IPOPT_TMP,
>      +                IPOPT_CARGS_L(IPOPT_TMP), IPOPT_TMP_STR
> 1220  CONTINUE
>
> This does not work:
>  param/leng/str:           1           4 <a lot of garbage>
>
> Why so much garbage? Would expect at maximum 4 characters of garbage ?!
>
> Any further help is very much appreciated. I need this to run first, 
> then I want
> to replace the old Ipopt with the current one. I started to dig into 
> Fortran on Friday only -
> and hope to have nothing to do with Fortran any more once I replaced 
> Ipopt. :)
>
> Currently I try to understand how to use this iso_c_binding module.
>
>> In general C/Fortran interoperability terms, I'd recommend you use the
>> iso_c_binding module.
>> Note that C-style strings are generally character*1 arrays on the
>> Fortran side. To determine length you'll need to pass the length
>> separately to the string (or call strlen from Fortran).
>>
>> This may mean you need a wrapper on the Fortran side that translates
>> arguments nicely and then calls your Fortran subroutine that takes
>> character(len=*) arguments. (If I've understood your question directly).
>>
>> Of course, the Fortran version of Ipopt has been replaced by the C++
>> version, so longer term you probably want to move away from
>> Ipopt-Fortran.
>>
>> Jonathan.
>>
>> On 26/03/12 10:15, Fabian Wein wrote:
>>> Hi,
>>>
>>> I have to use an Fortran code that uses Ipopt-Fortran from C++. I
>>> want to pass
>>> the Ipopt parameters from C++ via Fortran.
>>>
>>> Is there any example available on how to use the CHARACTER*(*) CARGS
>>> from
>>> C? I use gfortran.
> _______________________________________________
> Ipopt mailing list
> Ipopt at list.coin-or.org
> http://list.coin-or.org/mailman/listinfo/ipopt

-- 
Scanned by iCritical.


More information about the Ipopt mailing list