Re: Correct way to write a wrapper for C functions that accept/returnstrings

Discussion in 'C Programming' started by Phred Phungus, Mar 9, 2010.

  1. Eli Osherovich wrote:
    > What is the correct way to write a wrapper for C functions that accept/
    > return strings.
    >
    > For example
    >
    > void cfunc1(char* str)
    > char * cfunc2(void)
    >
    > Thank you.


    [x-posted]

    When you don't mention interop, this is just a question with C.
    --
    fred
     
    Phred Phungus, Mar 9, 2010
    #1
    1. Advertising

  2. Phred Phungus wrote:
    > Eli Osherovich wrote:
    > > What is the correct way to write a wrapper for C functions that accept/
    > > return strings.
    > >
    > > For example
    > >
    > > void cfunc1(char* str)
    > > char * cfunc2(void)
    > >

    >

    Acceting a string is easy. Just accept a char * or a const char * to a
    nul-terminated string.

    Returning strings you have to make a judgement call. Sometimes it is
    easier for caller to pass you a char * to a buffer which he controls,
    sometimes it is easier to return a char * containing allocated data.
    (Just rarely you want to retrn a char * to a static buffer). The fisrt
    method is likely to be faster and doesn't depend on malloc(), the
    second method is much less likely to allow a buffer overflow, and may
    the the only practical method if the length of the return string can't
    be predicted in advance.
     
    Malcolm McLean, Mar 9, 2010
    #2
    1. Advertising

  3. Re: Correct way to write a wrapper for C functions that

    In article <>, Malcolm McLean <> writes:

    > Returning strings you have to make a judgement call. Sometimes it is
    > easier for caller to pass you a char * to a buffer which he controls,
    > sometimes it is easier to return a char * containing allocated data.
    > (Just rarely you want to retrn a char * to a static buffer). The fisrt
    > method is likely to be faster and doesn't depend on malloc(), the
    > second method is much less likely to allow a buffer overflow, and may
    > the the only practical method if the length of the return string can't
    > be predicted in advance.


    Another possibility is to do double work, that is, communicate to the
    caller somehow if the string to store was truncated due to insufficient
    storage. The poor(er) sub-decision is then to let the caller iterate
    until the call succeeds; see strftime(). The better sub-decision is to
    return the amount of needed storage immediately; see snprintf(). The
    value returned in the latter case may be used to create a VLA of char.
    The contents of the target character array after a "truncated store" may
    be defined as "indeterminate" or "valid initial sequence", as the
    designer of the function likes.

    Cheers,
    lacos
     
    Ersek, Laszlo, Mar 9, 2010
    #3
  4. On Mar 9, 3:18 pm, Malcolm McLean <>
    wrote:
    > Phred Phungus wrote:
    > > Eli Osherovich wrote:
    > > > What is the correct way to write a wrapper for C functions that accept/
    > > > return strings.

    >
    > > > For example

    >
    > > > void cfunc1(char* str)
    > > > char * cfunc2(void)

    >
    > Acceting a string is easy. Just accept a char * or a const char * to a
    > nul-terminated string.
    >
    > Returning strings you have to make a judgement call. Sometimes it is
    > easier for caller to pass you a char * to a buffer which he controls,
    > sometimes it is easier to return a char * containing allocated data.
    > (Just rarely you want to retrn a char * to a static buffer). The fisrt
    > method is likely to be faster and doesn't depend on malloc(), the
    > second method is much less likely to allow a buffer overflow, and may
    > the the only practical method if the length of the return string can't
    > be predicted in advance.


    May be I do not understand you correctly... but my impression is you
    are talking about C not Fortran.
     
    Eli Osherovich, Mar 9, 2010
    #4
  5. Re: Correct way to write a wrapper for C functions that accept/return strings

    "Eli Osherovich" <> wrote in message
    news:...

    > > > What is the correct way to write a wrapper for C functions that
    > > > accept/
    > > > return strings.


    > > > For example


    > > > void cfunc1(char* str)
    > > > char * cfunc2(void)


    > May be I do not understand you correctly... but my impression is you
    > are talking about C not Fortran.


    C:\gfortran\clf\c_interop>type c_example.c
    #include <stdio.h>

    char c[] = {'C',' ','t','e','s','t',' ','m','e','s','s','a','g','e','\0'};

    void cfunc1(char* str)
    {
    printf("%s\n", str);
    }

    char *cfunc2(void)
    {
    return c;
    }

    C:\gfortran\clf\c_interop>type c_interop.f90
    module c_interop
    implicit none
    interface
    subroutine cfunc1(str) bind(C,name='cfunc1')
    use ISO_C_BINDING
    implicit none
    character(kind=C_CHAR) str(*)
    end subroutine cfunc1
    ! gfortran doesn't allow the following. I think it should.
    ! subroutine cfunc1a(str) bind(C,name='cfunc1')
    ! use ISO_C_BINDING
    ! implicit none
    ! type(C_PTR), value :: str
    ! end subroutine cfunc1a
    function cfunc2() bind(C,name='cfunc2')
    use ISO_C_BINDING
    implicit none
    type(C_PTR) cfunc2
    end function cfunc2
    end interface
    end module c_interop

    program test
    use ISO_C_BINDING
    use c_interop
    implicit none
    character(len=10,kind=C_CHAR), target :: test_msg
    character(kind=C_CHAR), pointer :: fp:))
    type(C_PTR) cp
    integer i

    test_msg = 'Testing'//achar(0)
    call cfunc1(test_msg)
    ! call cfunc1a(C_LOC(test_msg(1:1)))
    cp = cfunc2()
    i = 1
    do
    call C_F_POINTER(cp,fp,)
    if(fp(i) == achar(0)) exit
    i = i+1
    end do
    call sub(fp,i-1)
    contains
    subroutine sub(p,j)
    ! I know the next line was wrong, but check out the error message you get
    ! character(kind=C_PTR) p(*)
    character(kind=C_CHAR) p(*)
    integer j
    character(len=j) c

    c = transfer(p:)j),c)
    write(*,'(a)') c
    end subroutine sub
    end program test

    C:\gfortran\clf\c_interop>gcc -Wall -c c_example.c

    C:\gfortran\clf\c_interop>gfortran -Wall c_interop.f90
    c_example.o -oc_interop

    C:\gfortran\clf\c_interop>c_interop
    Testing
    C test message

    --
    write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
    6.0134700243160014d-154/),(/'x'/)); end
     
    James Van Buskirk, Mar 9, 2010
    #5
  6. Re: Correct way to write a wrapper for C functions that accept/return ?strings

    In comp.lang.fortran Eli Osherovich <> wrote:
    > On Mar 9, 3:18?pm, Malcolm McLean <>
    > wrote:
    >> Phred Phungus wrote:
    >> > Eli Osherovich wrote:
    >> > > What is the correct way to write a wrapper for C functions
    >> > > that accept/return strings.


    >> > > For example

    >
    >> > > void cfunc1(char* str)
    >> > > char * cfunc2(void)


    Do you mean a Fortran wrapper for the C routine, or a C wrapper,
    with the above declaration, for a Fortran routine?

    >> Acceting a string is easy. Just accept a char * or a
    >> const char * to a> nul-terminated string.


    >> Returning strings you have to make a judgement call. Sometimes it is
    >> easier for caller to pass you a char * to a buffer which he controls,
    >> sometimes it is easier to return a char * containing allocated data.
    >> (Just rarely you want to retrn a char * to a static buffer). The fisrt
    >> method is likely to be faster and doesn't depend on malloc(), the
    >> second method is much less likely to allow a buffer overflow, and may
    >> the the only practical method if the length of the return string can't
    >> be predicted in advance.


    The first and third are most commonly used by C library routines,
    and by user written functions. C programmers hate to have to keep
    track of memory malloc()ed by other routines.

    The string tokenizer, strtok(), returns pointers into the string
    supplied to it in the first call. ctime() returns a pointer to
    a static buffer. strdup() returns a pointer from malloc().

    > May be I do not understand you correctly... but my impression is you
    > are talking about C not Fortran.


    Well, you have to talk about C somewhere. As a C wrapper to a Fortran
    function, you have to do what other C programs can use. As a wrapper
    to a C funtion, you have to live with what the C function does.
    The above three are pretty much the choices you have.

    -- glen
     
    glen herrmannsfeldt, Mar 9, 2010
    #6
  7. On Mar 9, 6:47 pm, "James Van Buskirk" <> wrote:
    [snip]

    James, it works. Thank you.

    I have some questions about assumed-size vs assumed-shape arrays, but
    I should probably ask them in a separate thread.

    Thanks.
     
    Eli Osherovich, Mar 9, 2010
    #7
  8. Re: Correct way to write a wrapper for C functions that accept/return?strings

    On Mar 9, 7:58 pm, glen herrmannsfeldt <> wrote:
    > In comp.lang.fortran Eli Osherovich <> wrote:
    >
    > > On Mar 9, 3:18?pm, Malcolm McLean <>
    > > wrote:
    > >> Phred Phungus wrote:
    > >> > Eli Osherovich wrote:
    > >> > > What is the correct way to write a wrapper for C functions
    > >> > > that accept/return strings.
    > >> > > For example

    >
    > >> > > void cfunc1(char* str)
    > >> > > char * cfunc2(void)

    >
    > Do you mean a Fortran wrapper for the C routine, or a C wrapper,
    > with the above declaration, for a Fortran routine?
    >
    > >> Acceting a string is easy. Just accept a char * or a
    > >> const char * to a> nul-terminated string.
    > >> Returning strings you have to make a judgement call. Sometimes it is
    > >> easier for caller to pass you a char * to a buffer which he controls,
    > >> sometimes it is easier to return a char * containing allocated data.
    > >> (Just rarely you want to retrn a char * to a static buffer). The fisrt
    > >> method is likely to be faster and doesn't depend on malloc(), the
    > >> second method is much less likely to allow a buffer overflow, and may
    > >> the the only practical method if the length of the return string can't
    > >> be predicted in advance.

    >
    > The first and third are most commonly used by C library routines,
    > and by user written functions.  C programmers hate to have to keep
    > track of memory malloc()ed by other routines.
    >
    > The string tokenizer, strtok(), returns pointers into the string
    > supplied to it in the first call.  ctime() returns a pointer to
    > a static buffer.  strdup() returns a pointer from malloc().
    >
    > > May be I do not understand you correctly... but my impression is you
    > > are talking about C not Fortran.

    >
    > Well, you have to talk about C somewhere.  As a C wrapper to a Fortran
    > function, you have to do what other C programs can use.  As a wrapper
    > to a C funtion, you have to live with what the C function does.
    > The above three are pretty much the choices you have.
    >
    > -- glen


    I want a Fortran wrapper for C functions whose prototypes were given
    in the first message.
     
    Eli Osherovich, Mar 9, 2010
    #8
  9. Re: Correct way to write a wrapper for C functions that accept/return ??strings

    In comp.lang.fortran Eli Osherovich <> wrote:
    > On Mar 9, 7:58?pm, glen herrmannsfeldt <> wrote:
    >> In comp.lang.fortran Eli Osherovich <> wrote:
    >> > On Mar 9, 3:18?pm, Malcolm McLean <>

    (snip)
    >> >> Returning strings you have to make a judgement call. Sometimes it is
    >> >> easier for caller to pass you a char * to a buffer which he controls,
    >> >> sometimes it is easier to return a char * containing allocated data.
    >> >> (Just rarely you want to retrn a char * to a static buffer). The fisrt
    >> >> method is likely to be faster and doesn't depend on malloc(), the
    >> >> second method is much less likely to allow a buffer overflow, and may
    >> >> the the only practical method if the length of the return string can't
    >> >> be predicted in advance.


    >> The first and third are most commonly used by C library routines,
    >> and by user written functions. ?C programmers hate to have to keep
    >> track of memory malloc()ed by other routines.

    (snip)
    >> > May be I do not understand you correctly... but my impression is you
    >> > are talking about C not Fortran.


    >> Well, you have to talk about C somewhere. ?As a C wrapper to a Fortran
    >> function, you have to do what other C programs can use. ?As a wrapper
    >> to a C funtion, you have to live with what the C function does.
    >> The above three are pretty much the choices you have.


    > I want a Fortran wrapper for C functions whose prototypes were given
    > in the first message.


    Where does the (char*) return value come from? Presumably one
    of the sources indicated above.

    The right answer is that they are of TYPE(C_PTR), but often that
    isn't what you want.

    You can, for example, pass an array of CHARACTER(C_CHAR) to a C
    routine expecting a (char *) if you don't put VALUE on the interface.

    You can't really do that for the return value, though.

    If the C routine returns a pointer to static storage
    (usually of known size), then the Fortran routine can return
    CHARACTER*(size), which you copy from the returned C value.

    If the C routine returns malloc()ed space, ALLOCATE an
    appropriate sized CHARACTER variable, copy the value,
    free() the pointer, and return. (That is, if functions can
    return ALLOCATABLE CHARACTER variables.)

    If the function returns a pointer into the input string, you
    might return an integer offset. For example, the C library
    routine strstr(), sometimes known as index(), returns a pointer
    into the argument string. You can't really do that in Fortran,
    but returning the difference between the two pointers makes sense.
    (strstr() can also return NULL, which you have to consider separately.)
    Unfortunately, subtracting TYPE(C_PTR) in Fortran isn't easy.

    -- glen
     
    glen herrmannsfeldt, Mar 9, 2010
    #9
  10. James Van Buskirk wrote:

    > C:\gfortran\clf\c_interop>type c_example.c


    James' example works perfectly. A big part of the problem with interop
    is figuring out which part is C and which part is fortran. I always
    identify one as caller.


    $ gcc -D_GNU_SOURCE -std=c99 -Wall -Wextra g2.c -c -o cfunc.o
    $ ls
    9vx-0.12 a1.c~ cfunc.o g1.c g2.c out
    a1.c backups1 fortran_stuff g1.c~ g2.c~ unleashed

    So far so good.

    $ gfortran -D_GNU_SOURCE -Wall -Wextra caller1.f90 cfunc.o -o out
    $ ./out
    Testing
    C test message
    $ cat caller1.f90


    module c_interop
    implicit none
    interface
    subroutine cfunc1(str) bind(C,name='cfunc1')
    use ISO_C_BINDING
    implicit none
    character(kind=C_CHAR) str(*)
    end subroutine cfunc1
    ! gfortran doesn't allow the following. I think it should.
    ! subroutine cfunc1a(str) bind(C,name='cfunc1')
    ! use ISO_C_BINDING
    ! implicit none
    ! type(C_PTR), value :: str
    ! end subroutine cfunc1a
    function cfunc2() bind(C,name='cfunc2')
    use ISO_C_BINDING
    implicit none
    type(C_PTR) cfunc2
    end function cfunc2
    end interface
    end module c_interop

    program test
    use ISO_C_BINDING
    use c_interop
    implicit none
    character(len=10,kind=C_CHAR), target :: test_msg
    character(kind=C_CHAR), pointer :: fp:))
    type(C_PTR) cp
    integer i

    test_msg = 'Testing'//achar(0)
    call cfunc1(test_msg)
    ! call cfunc1a(C_LOC(test_msg(1:1)))
    cp = cfunc2()
    i = 1
    do
    call C_F_POINTER(cp,fp,)
    if(fp(i) == achar(0)) exit
    i = i+1
    end do
    call sub(fp,i-1)
    contains
    subroutine sub(p,j)
    ! I know the next line was wrong, but check out the error message you get
    ! character(kind=C_PTR) p(*)
    character(kind=C_CHAR) p(*)
    integer j
    character(len=j) c

    c = transfer(p:)j),c)
    write(*,'(a)') c
    end subroutine sub
    end program test

    ! gfortran -D_GNU_SOURCE -Wall -Wextra caller1.f90 cfunc.o -o out
    $ cat cfunc.c
    cat: cfunc.c: No such file or directory
    $ cat g2.c


    #include <stdio.h>

    char c[] = {'C',' ','t','e','s','t',' ','m','e','s','s','a','g','e','\0'};

    void cfunc1(char* str)
    {
    printf("%s\n", str);
    }

    char *cfunc2(void)
    {
    return c;
    }


    // gcc -D_GNU_SOURCE -std=c99 -Wall -Wextra g2.c -c -o cfunc.o
    $

    As for this part:

    ! I know the next line was wrong, but check out the error message you get
    ! character(kind=C_PTR) p(*)

    , gfortran has a lot to say:

    $ gfortran -D_GNU_SOURCE -Wall -Wextra caller2.f90 cfunc.o -o out
    caller2.f90:48.27:

    character(kind=C_PTR) p(*)
    1
    Error: Syntax error in structure constructor at (1)
    caller2.f90:53.24:

    c = transfer(p:)j),c)
    1
    Error: Syntax error in argument list at (1)
    caller2.f90:46.22:

    subroutine sub(p,j)
    1
    Error: Symbol 'p' at (1) has no IMPLICIT type
    caller2.f90:44.12:

    call sub(fp,i-1)
    1
    Error: Type mismatch in argument 'p' at (1); passed CHARACTER(1) to UNKNOWN
    $
    --
    fred
     
    Phred Phungus, Mar 10, 2010
    #10
  11. On 9 Mar, 15:53, Eli Osherovich <> wrote:
    >
    > May be I do not understand you correctly... but my impression is you
    > are talking about C not Fortran.- Hide quoted text -
    >

    I got the wrong end of the stick. We have a lot of non-native English
    speakers here who use terms like "wrapper" incorrectly. I assumed you
    meant "interface" rather than Fortran wrapper.

    In Fortran 77 an integer is passed along with a string to give its
    length. So to call a C string functions it's

    void cfunc_(char *str, int N)

    note it's "int N", not "int * N"

    The easiest way to return a string is simply to write to the buffer
    you used to pass the input.

    (A question for middlebies: should the C function use size_t
    internally? What are the pros and cons of doign so?).
     
    Dr Malcolm McLean, Mar 10, 2010
    #11
  12. Dr Malcolm McLean wrote:
    > On 9 Mar, 15:53, Eli Osherovich <> wrote:
    >> May be I do not understand you correctly... but my impression is you
    >> are talking about C not Fortran.- Hide quoted text -
    >>

    > I got the wrong end of the stick. We have a lot of non-native English
    > speakers here who use terms like "wrapper" incorrectly. I assumed you
    > meant "interface" rather than Fortran wrapper.


    Right. I think the word "interface" is better than "wrapper." The wiki
    isn't very good here:

    http://en.wikipedia.org/wiki/Wrapper_function
    >
    > In Fortran 77 an integer is passed along with a string to give its
    > length. So to call a C string functions it's
    >
    > void cfunc_(char *str, int N)
    >
    > note it's "int N", not "int * N"
    >
    > The easiest way to return a string is simply to write to the buffer
    > you used to pass the input.


    I hadn't really thought about interop with a buffer.
    >
    > (A question for middlebies: should the C function use size_t
    > internally? What are the pros and cons of doign so?).


    One non con would be the size of the object, which is very small
    compared to machine constraints.
    --
    fred
     
    Phred Phungus, Mar 30, 2010
    #12
  13. Re: Correct way to write a wrapper for C functions that accept/return strings

    Phred Phungus <> wrote:

    > Dr Malcolm McLean wrote:
    > > On 9 Mar, 15:53, Eli Osherovich <> wrote:
    > >> May be I do not understand you correctly... but my impression is you
    > >> are talking about C not Fortran.- Hide quoted text -
    > >>

    > > I got the wrong end of the stick. We have a lot of non-native English
    > > speakers here who use terms like "wrapper" incorrectly. I assumed you
    > > meant "interface" rather than Fortran wrapper.

    >
    > Right. I think the word "interface" is better than "wrapper."


    However, "interface" has a very specific Fortran meaning, independent of
    your native language. That's part of the Fortran language. If you use
    "interface" to mean something else in Fortran, I can pretty much
    guarantee that you are going to confuse some people... myself included.

    --
    Richard Maine | Good judgment comes from experience;
    email: last name at domain . net | experience comes from bad judgment.
    domain: summertriangle | -- Mark Twain
     
    Richard Maine, Mar 30, 2010
    #13
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. QQ

    Functions that accept various type?

    QQ, Dec 11, 2004, in forum: C Programming
    Replies:
    8
    Views:
    366
    Old Wolf
    Dec 14, 2004
  2. John Nagle
    Replies:
    0
    Views:
    320
    John Nagle
    Feb 14, 2009
  3. m0shbear
    Replies:
    2
    Views:
    358
  4. Ashley Wharton
    Replies:
    4
    Views:
    117
    Robert Klemme
    Feb 12, 2008
  5. Replies:
    7
    Views:
    87
    Chris Angelico
    Aug 3, 2013
Loading...

Share This Page