ISO C Binding: Pointer to a pointer of pointers: ***argv 
Author Message
 ISO C Binding: Pointer to a pointer of pointers: ***argv

Hello,

I need to call
  void test_c (int *argc, ***argv)

and I somehow fail to create the necessary fortran program. The
program below works for
  void test_c (int *arg, **argv)

Any idea how to achieve the needed ***argv? The only thing I got so
far is crashing programs and complaining compilers.

Tobias

My first attempt for *argv[] instead of **argv[], not very elegant and
leaking memory:
-----------------
#include <stdio.h>

void test_c(int *argc, char *argv[])
{
  int i;
  printf("Number of arguments: %d\n", *argc);
  for (i=0; i < *argc; i++)
    printf("ARG %d: '%s'\n", i, argv[i]);

Quote:
}

-----------------
-----------------
use iso_c_binding
implicit none

interface
  subroutine test_c(i,a) bind(c)
    import
    integer(c_int) :: i
    type(c_ptr) :: a(*)
  end subroutine
end interface

character(len=256,kind=c_char) :: arg
character(len=1,kind=c_char), dimension(:),pointer :: carg
type(c_ptr), pointer :: argv(:)
integer :: max, i,strlen,j

max = COMMAND_ARGUMENT_COUNT()
allocate(argv(0:max))

do i = 0, max
  call GET_COMMAND_ARGUMENT(i,arg)
  strlen = len(trim(arg))
  allocate(carg(0:strlen))
  do j = 0, strlen-1
    carg(j) = arg(j+1:j+1)
  end do
  carg(strlen) = c_null_char
  argv(i) = c_loc(carg(0))
end do
max = max + 1
call test_c(max, argv)
end
-----------------



Wed, 19 Aug 2009 01:59:11 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv

Quote:

> I need to call
>   void test_c (int *argc, ***argv)

 > character(len=256,kind=c_char) :: arg
 > character(len=1,kind=c_char), dimension(:),pointer :: carg
 > type(c_ptr), pointer :: argv(:)
 > integer :: max, i,strlen,j
 >
 > max = COMMAND_ARGUMENT_COUNT()
 > allocate(argv(0:max))
 >
 > do i = 0, max
 >   call GET_COMMAND_ARGUMENT(i,arg)
 >   strlen = len(trim(arg))
 >   allocate(carg(0:strlen))
 >   do j = 0, strlen-1
 >     carg(j) = arg(j+1:j+1)
 >   end do
 >   carg(strlen) = c_null_char
 >   argv(i) = c_loc(carg(0))
 > end do
 > max = max + 1
 > call test_c(max, argv)
 > end

I would have thought

    call test_c(c_loc(max),c_loc(argv))

-- glen



Wed, 19 Aug 2009 03:44:51 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv

Quote:
> I would have thought
>     call test_c(c_loc(max),c_loc(argv))

This indeed works with gfortran [fortran-experiments] after I changed
"pointer" into "allocatable, target". (With g95 and NAG f95 I get
internal compiler errors, and sunf95 does not like my first c_loc.)

Thanks,

Tobias

PS: Below, you find my hello-world GTK+ program. It does merely show a
window, cf. http://www.gtk.org/tutorial/c39.html

module GTK
 use iso_c_binding, only: c_int
 implicit none
 interface
   subroutine gtk_widget_show (window) bind(c)
     use iso_c_binding, only: c_ptr
     type(c_ptr) :: window
   end subroutine

   function gtk_window_new(type) bind(c)
     use iso_c_binding, only: c_ptr, c_int
     integer(c_int), value :: type
     type(c_ptr), pointer  :: gtk_window_new
   end function gtk_window_new

   subroutine gtk_main() bind(c)
   end subroutine gtk_main

   ! actually, this is a function returning "gulong"
   subroutine g_signal_connectt(instance, detailed_signal, c_handler,
gobject);
     use iso_c_binding, only: c_ptr, c_char
     character(c_char) :: detailed_signal(*)
     type(ptr)         :: instance, c_handler, gobject
   end subroutine g_signal_connect
 end interface

 integer(c_int), parameter :: GTK_WINDOW_TOPLEVEL = 0

contains

  subroutine gtk_init()
    use iso_c_binding, only: c_ptr, c_char, c_int, c_null_char, c_loc
    interface
      subroutine gtk_init_real(argc,argv) bind(c,name='gtk_init')
        use iso_c_binding, only: c_int, c_ptr
        integer(c_int) :: argc
        type(c_ptr)    :: argv
      end subroutine
    end interface

    character(len=256,kind=c_char) :: arg
    character(len=1,kind=c_char), dimension(:),pointer :: carg
    type(c_ptr), allocatable, target :: argv(:)
    integer(c_int) :: argc, strlen, i, j

    argc = command_argument_count()
    allocate(argv(0:argc))

    do i = 0, argc
      call get_command_argument(i,arg,strlen)
      allocate(carg(0:strlen))
      do j = 0, strlen-1
        carg(j) = arg(j+1:j+1)
      end do
      carg(strlen) = c_null_char
      argv(i) = c_loc(carg(0))
    end do
    argc = argc + 1
    call gtk_init_real(argc, c_loc(argv))
  end subroutine gtk_init

end module GTK

program guiF
 use iso_c_binding, only: c_ptr, c_null_ptr
 use gtk
 implicit none

 type(c_ptr), pointer :: window
 call gtk_init ()
 window => gtk_window_new (GTK_WINDOW_TOPLEVEL)
 call gtk_widget_show (window)

 call gtk_main ()
end program gui



Wed, 19 Aug 2009 06:26:25 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv


Quote:

>> I would have thought
>>     call test_c(c_loc(max),c_loc(argv))

> This indeed works with gfortran [fortran-experiments] after I changed
> "pointer" into "allocatable, target". (With g95 and NAG f95 I get
> internal compiler errors, and sunf95 does not like my first c_loc.)

> Thanks,

> Tobias

> PS: Below, you find my hello-world GTK+ program. It does merely show a
> window, cf. http://www.gtk.org/tutorial/c39.html

> module GTK
> use iso_c_binding, only: c_int
> implicit none
> interface
>   subroutine gtk_widget_show (window) bind(c)
>     use iso_c_binding, only: c_ptr
>     type(c_ptr) :: window
>   end subroutine

>   function gtk_window_new(type) bind(c)
>     use iso_c_binding, only: c_ptr, c_int
>     integer(c_int), value :: type
>     type(c_ptr), pointer  :: gtk_window_new
>   end function gtk_window_new

>   subroutine gtk_main() bind(c)
>   end subroutine gtk_main

>   ! actually, this is a function returning "gulong"
>   subroutine g_signal_connectt(instance, detailed_signal, c_handler,
> gobject);
>     use iso_c_binding, only: c_ptr, c_char
>     character(c_char) :: detailed_signal(*)
>     type(ptr)         :: instance, c_handler, gobject
>   end subroutine g_signal_connect
> end interface

> integer(c_int), parameter :: GTK_WINDOW_TOPLEVEL = 0

> contains

>  subroutine gtk_init()
>    use iso_c_binding, only: c_ptr, c_char, c_int, c_null_char, c_loc
>    interface
>      subroutine gtk_init_real(argc,argv) bind(c,name='gtk_init')
>        use iso_c_binding, only: c_int, c_ptr
>        integer(c_int) :: argc
>        type(c_ptr)    :: argv
>      end subroutine
>    end interface

>    character(len=256,kind=c_char) :: arg
>    character(len=1,kind=c_char), dimension(:),pointer :: carg
>    type(c_ptr), allocatable, target :: argv(:)
>    integer(c_int) :: argc, strlen, i, j

>    argc = command_argument_count()
>    allocate(argv(0:argc))

>    do i = 0, argc
>      call get_command_argument(i,arg,strlen)
>      allocate(carg(0:strlen))
>      do j = 0, strlen-1
>        carg(j) = arg(j+1:j+1)
>      end do
>      carg(strlen) = c_null_char
>      argv(i) = c_loc(carg(0))
>    end do
>    argc = argc + 1
>    call gtk_init_real(argc, c_loc(argv))
>  end subroutine gtk_init

> end module GTK

> program guiF
> use iso_c_binding, only: c_ptr, c_null_ptr
> use gtk
> implicit none

> type(c_ptr), pointer :: window
> call gtk_init ()
> window => gtk_window_new (GTK_WINDOW_TOPLEVEL)
> call gtk_widget_show (window)

> call gtk_main ()
> end program gui

I reply for selfish reasons: I want the above source in my "sent items."

I'm not at all clear whether this will run on the compiler I use.  But if
Glen is the architect, I'll be happy to engage on a fool's errand.  LS



Wed, 19 Aug 2009 06:43:13 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv

Quote:

> > I would have thought
> >     call test_c(c_loc(max),c_loc(argv))

> This indeed works with gfortran [fortran-experiments] after I changed
> "pointer" into "allocatable, target". (With g95 and NAG f95 I get
> internal compiler errors, and sunf95 does not like my first c_loc.)

The Fortran 2003 versions of the C bindings do not allow
array pointers as arguments to C_LOC.  The variable MAX would
be allowed as an argument to C_LOC if you give it the TARGET
attribute.

Bob Corbett



Wed, 19 Aug 2009 10:34:45 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv
Hi,


Quote:
> The Fortran 2003 versions of the C bindings do not allow
> array pointers as arguments to C_LOC.

Yes, I found out as I reread the standard, but, as written, using
"allocatable, dimension(:), target" is allowed for c_loc().

Talking about sunf95 (8.3 Linux_i386 Build35_2 2006/12/04), it should
not reject
 character(len=1,kind=c_char), dimension(:),pointer :: carg
 argv(i) = c_loc(carg(0))

Reason: carg(0) is not an array pointer, it is merely a scalar
pointer. In addition, sunf95 does not support Bind(c) for functions,
it only supports bind(c) for subroutines.

 * * *

I have another question regarding type(c_ptr) and (void*) returning C
functions.

Assuming the following C routines:
--------------------
#include <malloc.h>
#include <stdio.h>

void *create (void)
{
  int *a;
  a = malloc (sizeof (a));
  *a = 444;
  return a;

Quote:
}

void show (int *a)
{
  if (*a == 444)
    printf ("SUCCESS (%d)\n", *a);
  else
    printf ("FAILED: Expected 444, received %d\n", *a);
Quote:
}

--------------------

I now want to do the following
--------------------
void *create (void);
void show (void *a);

int main ( )
{
  void *ptr;
  ptr = create ();
  show (ptr);
  return 0;

Quote:
}

--------------------

but I want to do it in Fortran. Is the following program correct?
--------------------
program main
use iso_c_binding, only: c_ptr
implicit none
interface
  function create() bind(c)
    use iso_c_binding, only: c_ptr
    type(c_ptr) :: create
  end function create
  subroutine show(a) bind(c)
    import :: c_ptr
    type(c_ptr) :: a
  end subroutine show
end interface

type(c_ptr) :: ptr
ptr = create()
call show(ptr)
end program main
--------------------

For the C program, I get the expected
  SUCCESS (444)
but the gfortran-, g95- and NAG-f95-compiled programs print:
  FAILED: Expected 444, received 6325536
  FAILED: Expected 444, received 6316048
  FAILED: Expected 444, received 6701936

Is my program correct or do I miss something?

Tobias

PS: Below my corrected GTK+ Hello World program; I believe it is now
correct and should work once the compiler bugs are fixed.

module GTK
 use iso_c_binding, only: c_int
 implicit none
 interface
   subroutine gtk_widget_show (window) bind(c)
     use iso_c_binding, only: c_ptr
     type(c_ptr) :: window
   end subroutine

   function gtk_window_new(type) bind(c)
     use iso_c_binding, only: c_ptr, c_int
     integer(c_int), value :: type
     type(c_ptr) :: gtk_window_new
   end function gtk_window_new

   subroutine gtk_main() bind(c)
   end subroutine gtk_main
 end interface

 integer(c_int), parameter :: GTK_WINDOW_TOPLEVEL = 0

contains

  subroutine gtk_init()
    use iso_c_binding, only: c_ptr, c_char, c_int, c_null_char, c_loc
    interface
      subroutine gtk_init_real(argc,argv) bind(c,name='gtk_init')
        use iso_c_binding, only: c_int, c_ptr
        integer(c_int) :: argc
        type(c_ptr)    :: argv
      end subroutine
    end interface

    character(len=256,kind=c_char) :: arg
    character(len=1,kind=c_char), dimension(:),pointer :: carg
    type(c_ptr), allocatable, target :: argv(:)
    integer(c_int) :: argc, strlen, i, j

    argc = command_argument_count()
    allocate(argv(0:argc))

    do i = 0, argc
      call get_command_argument(i,arg,strlen)
      allocate(carg(0:strlen))
      do j = 0, strlen-1
        carg(j) = arg(j+1:j+1)
      end do
      carg(strlen) = c_null_char
      argv(i) = c_loc(carg(0))
    end do
    argc = argc + 1
    call gtk_init_real(argc, c_loc(argv))
  end subroutine gtk_init

end module GTK

program guiF
 use iso_c_binding, only: c_ptr
 use gtk
 implicit none

 type(c_ptr) :: window
 call gtk_init ()
 window = gtk_window_new (GTK_WINDOW_TOPLEVEL)
 call gtk_widget_show (window)
 call gtk_main ()
end program guiF



Wed, 19 Aug 2009 17:26:09 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv
(snip)

Quote:
> I have another question regarding type(c_ptr) and (void*) returning C
> functions.
> Assuming the following C routines:
> --------------------
> #include <malloc.h>
> #include <stdio.h>
> void *create (void)
> {
>   int *a;
>   a = malloc (sizeof (a));
>   *a = 444;
>   return a;
> }
> void show (int *a)
> {
>   if (*a == 444)
>     printf ("SUCCESS (%d)\n", *a);
>   else
>     printf ("FAILED: Expected 444, received %d\n", *a);
> }
> --------------------
> I now want to do the following
> --------------------
> void *create (void);
> void show (void *a);

> int main ( )
> {
>   void *ptr;
>   ptr = create ();
>   show (ptr);
>   return 0;
> }
> --------------------
> but I want to do it in Fortran. Is the following program correct?
> --------------------
> program main
> use iso_c_binding, only: c_ptr
> implicit none
> interface
>   function create() bind(c)
>     use iso_c_binding, only: c_ptr
>     type(c_ptr) :: create
>   end function create
>   subroutine show(a) bind(c)
>     import :: c_ptr
>     type(c_ptr) :: a
>   end subroutine show
> end interface

I believe:

type(c_ptr), value :: a

to agree with C's call by value.

Your previous program called test_c(max,argv), for the C function
test_c(int *max, char **argv)

For dummy arguments without the value attribute, Fortran, as usual,
passes c_loc() of the argument.

 From note 15.22:

    "A C pointer may correspond to a Fortran dummy argument of
    type C PTR or to a Fortran scalar that does not have the VALUE
    attribute. In the above example, the C pointers j and k
    correspond to the Fortran scalars J and K, respectively, and
    the C pointer m corresponds to the Fortran dummy argument M
    of type C PTR."

Quote:
> type(c_ptr) :: ptr
> ptr = create()
> call show(ptr)
> end program main
> --------------------

> For the C program, I get the expected
>   SUCCESS (444)
> but the gfortran-, g95- and NAG-f95-compiled programs print:
>   FAILED: Expected 444, received 6325536
>   FAILED: Expected 444, received 6316048
>   FAILED: Expected 444, received 6701936

> Is my program correct or do I miss something?

(snip)

-- glen



Wed, 19 Aug 2009 20:05:06 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv


Quote:
> >   subroutine show(a) bind(c)
> >     import :: c_ptr
> >     type(c_ptr) :: a
> >   end subroutine show
> > end interface
> I believe:
> type(c_ptr), value :: a
> to agree with C's call by value.

Indeed, with that change it works in gfortran. And thinking of it, it
makes sense: I don't want to know the address of the pointer itself
but only of its target.

Tobias

PS: For the GTK module, change:

   subroutine gtk_widget_show (window) bind(c)
     use iso_c_binding, only: c_ptr
     type(c_ptr), VALUE :: window



Wed, 19 Aug 2009 21:40:40 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv

Quote:

>  character(len=1,kind=c_char), dimension(:),pointer :: carg
>  argv(i) = c_loc(carg(0))

> carg(0) is not an array pointer, it is merely a scalar
> pointer.

No. carg(0) is not  a pointer at all. The only pointer here is carg.
carg(0) would be an element of the target... assuming that carg is
associated and that carg(0) is in bounds; otherwise, it is invalid.

I think your conclusion is correct - that c_loc(carg(0)) should be valid
(given the above conditions,which aren't evident in the snippet shown).
But your reason is wrong.

--
Richard Maine                    | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle           |  -- Mark Twain



Thu, 20 Aug 2009 01:09:55 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv

Quote:


>>>  subroutine show(a) bind(c)
>>>    import :: c_ptr
>>>    type(c_ptr) :: a
>>>  end subroutine show
>>>end interface
>>I believe:
>>type(c_ptr), value :: a
>>to agree with C's call by value.
> Indeed, with that change it works in gfortran. And thinking of it, it
> makes sense: I don't want to know the address of the pointer itself
> but only of its target.

I did have to go back and look at the previous one.  I figured out
that it needed c_loc() without going all the way through the code,
and then had to check why it didn't need value.

-- glen



Thu, 20 Aug 2009 02:42:43 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv
(snip)

Quote:
> The Fortran 2003 versions of the C bindings do not allow
> array pointers as arguments to C_LOC.

C_LOC() says its argument shall:

  "(1) be
      (a) a procedure that is interoperable, or
      (b) a procedure pointer associated with an interoperable procedure,
   (2) have interoperable type and type parameters and be
      (a) a variable that has the TARGET attribute and is interoperable,
      (b) an allocated allocatable variable that has the TARGET
          attribute, or
      (c) an associated scalar pointer, or
   (3) be a nonpolymorphic scalar and have no nonkind type parameters
       and be
      (a) a nonallocatable, nonpointer variable that has the TARGET
          attribute"

I might believe that there should be more ORs in there.

It does seem to exclude array pointers, which is what the OP had.
Is a pointer to the first element of an array pointer fine?

-- glen



Thu, 20 Aug 2009 03:37:19 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv

Quote:

> Is a pointer to the first element of an array pointer fine?

Is that supposed to be relevant to the code shown? It isn't. As I
mentioned elsewhere, the form carg(0) is not a pointer at all, much less
a "pointer to the first element of an array pointer". It is, however, "a
nonallocatable, nonpointer variable that has the TARGET attribute."

carg is a pointer. carg(0) is not.

Note also that, if you do generate a pointer to carg(0) and pass that to
C , the remaining elements of carg are not guaranteed to be accessible.
You just have a pointer to a scalar. I think that even in C, you aren't
technically allowed to increment a pointer to a scalar, but I'm a bit
hazy on those details. (whether it will likely work anyway is another
question).

--
Richard Maine                    | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle           |  -- Mark Twain



Thu, 20 Aug 2009 04:00:41 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv

Quote:


>>Is a pointer to the first element of an array pointer fine?
> Is that supposed to be relevant to the code shown? It isn't. As I
> mentioned elsewhere, the form carg(0) is not a pointer at all, much less
> a "pointer to the first element of an array pointer". It is, however, "a
> nonallocatable, nonpointer variable that has the TARGET attribute."

It was supposed to be about argv.

Quote:
> carg is a pointer. carg(0) is not.

In C a pointer to an array (or struct) is equivalent to a
pointer to the first element of an array (or struct).  I don't
know if that applies to carg or argv in the program given.

Quote:
> Note also that, if you do generate a pointer to carg(0) and pass that to
> C , the remaining elements of carg are not guaranteed to be accessible.
> You just have a pointer to a scalar. I think that even in C, you aren't
> technically allowed to increment a pointer to a scalar, but I'm a bit
> hazy on those details. (whether it will likely work anyway is another
> question).

The C rule, which I believe also applied to pointers to scalars, is
that you are allowed to point one past the end of the object pointed
to, though you aren't allowed to dereference such pointers.
A pointer to an array element can be incremented or decremented
to point to any element of that array.

I would say that it is up to the programmer to be sure that
makes sense for a given C_PTR, especially that only contiguous
arrays are used.

-- glen



Thu, 20 Aug 2009 18:23:23 GMT  
 ISO C Binding: Pointer to a pointer of pointers: ***argv

Quote:


> > carg is a pointer. carg(0) is not.

> In C a pointer to an array (or struct) is equivalent to a
> pointer to the first element of an array (or struct).  I don't
> know if that applies to carg or argv in the program given.

We seem to be doing our usual miscomunication thing. While I had a C
question later, this wasn't it. This part is Fortran. In Fortran which
is whatthis code is, carg(0) is nogt a pointer. Period. It doesn't
matter what C says about vaguely ralated things (and Fortran pointers
aren't much like C pointers anyway).

Quote:
> > Note also that, if you do generate a pointer to carg(0) and pass that to
> > C , the remaining elements of carg are not guaranteed to be accessible.
> > You just have a pointer to a scalar. I think that even in C, you aren't
> > technically allowed to increment a pointer to a scalar, but I'm a bit
> > hazy on those details. (whether it will likely work anyway is another
> > question).

> The C rule, which I believe also applied to pointers to scalars, is
> that you are allowed to point one past the end of the object pointed
> to, though you aren't allowed to dereference such pointers.
> A pointer to an array element can be incremented or decremented
> to point to any element of that array.

That sounds plausible. I hadn't known about the "one past" rule, but
with the prohibition against dereferencing, it fits. In this case, what
gets passed from Fortran is a pointer to a scalar. It doesn't matter
that teh scalaris the first element of an array because that part is in
Fortran. It is *VERY* relevant that Fortran arrays aren't the same as C
ones.

Quote:
> I would say that it is up to the programmer to be sure that
> makes sense for a given C_PTR, especially that only contiguous
> arrays are used.

I'd agree with that as practical advice. But I'll note that you have
just shown why it is nonstandard. It might well (probaby will) work
inpractice, but it is nonstandard.

--
Richard Maine                    | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle           |  -- Mark Twain



Fri, 21 Aug 2009 01:09:13 GMT  
 
 [ 14 post ] 

 Relevant Pages 

1. Pointers to pointers possible?

2. A pointer to an array of pointers

3. Pointer to pointer with LabVIEW 4.1?

4. pointers and pointers.

5. Returning Pointer To Pointer From Function

6. Implementing pointers to pointers in Ada

7. pointer to pointer to field / dynamic field

8. A couple of simple pointer questions (targets, arrays of pointers)

9. Deallocation of a pointer which points to a type containing allocated pointers

10. fortran 90/95 pointers vs C pointers

11. pointers to pointers

12. Pointer to pointer to BSTR?

 

 
Powered by phpBB® Forum Software