Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

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

1 view
Skip to first unread message

Phred Phungus

unread,
Mar 9, 2010, 4:45:37 AM3/9/10
to
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

Malcolm McLean

unread,
Mar 9, 2010, 8:18:13 AM3/9/10
to

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.

Ersek, Laszlo

unread,
Mar 9, 2010, 8:54:02 AM3/9/10
to

> 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

Eli Osherovich

unread,
Mar 9, 2010, 10:53:11 AM3/9/10
to
On Mar 9, 3:18 pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
wrote:

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

James Van Buskirk

unread,
Mar 9, 2010, 11:47:17 AM3/9/10
to
"Eli Osherovich" <eli.osh...@gmail.com> wrote in message
news:3754018c-22d7-446f...@g11g2000yqe.googlegroups.com...

> > > 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,[i])
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


glen herrmannsfeldt

unread,
Mar 9, 2010, 12:58:16 PM3/9/10
to
In comp.lang.fortran Eli Osherovich <eli.osh...@gmail.com> wrote:
> On Mar 9, 3:18?pm, Malcolm McLean <malcolm.mcle...@btinternet.com>

> 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

Eli Osherovich

unread,
Mar 9, 2010, 1:57:02 PM3/9/10
to
On Mar 9, 6:47 pm, "James Van Buskirk" <not_va...@comcast.net> 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

unread,
Mar 9, 2010, 1:57:52 PM3/9/10
to
On Mar 9, 7:58 pm, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:

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

glen herrmannsfeldt

unread,
Mar 9, 2010, 2:39:49 PM3/9/10
to
In comp.lang.fortran Eli Osherovich <eli.osh...@gmail.com> wrote:
> On Mar 9, 7:58?pm, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
>> In comp.lang.fortran Eli Osherovich <eli.osherov...@gmail.com> wrote:
>> > On Mar 9, 3:18?pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
(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

Phred Phungus

unread,
Mar 9, 2010, 7:07:48 PM3/9/10
to
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

! 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

Dr Malcolm McLean

unread,
Mar 10, 2010, 4:39:00 PM3/10/10
to
On 9 Mar, 15:53, Eli Osherovich <eli.osherov...@gmail.com> 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?).

Phred Phungus

unread,
Mar 30, 2010, 12:07:22 AM3/30/10
to
Dr Malcolm McLean wrote:
> On 9 Mar, 15:53, Eli Osherovich <eli.osherov...@gmail.com> 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

Richard Maine

unread,
Mar 30, 2010, 12:26:49 AM3/30/10
to
Phred Phungus <Ph...@example.invalid> wrote:

> Dr Malcolm McLean wrote:
> > On 9 Mar, 15:53, Eli Osherovich <eli.osherov...@gmail.com> 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

0 new messages