problem with mixed c and fortran code

  • Follow


(question forwarded from from gnu.gcc.help)

Hi,

hope someone can explain what happens in the code below.
I expected the two different pointers cp1 and cp2 to stay different, but 
after the fortran function they point to the same adress. Is that correct?
With a similar fortran main program there is no mixup.

$ cat f.f
      function fcall_1(cin)
      implicit none
      character cin,fcall_1
      character cout
      cout='B'
      fcall_1=cout
      return
      end

$ cat c.c
#include <stdlib.h>
#include <stdio.h>

unsigned char * fcall_1_(unsigned char *);

int main(void)
{
  unsigned char c1,c2,*cp1,*cp2;

  c1='F';cp1=&c1;
  c2='A';cp2=&c2;
  printf("Printing from c before fortran call:\tcp1=%p('%c'), cp2=%p('%c')
\n",cp1,c1,cp2,c2);
  cp2=fcall_1_(cp1);
  c2=*cp2;
  printf("Printing from c after fortran call:\tcp1=%p('%c'), cp2=%p('%c')
\n",cp1,c1,cp2,c2);

  return 0;
}
$ ./cf.out 
Printing from c before fortran call:	cp1=0xbfdc8b67('F'),
cp2=0xbfdc8b66('A')
Printing from c after fortran call:	cp1=0xbfdc8b67('B'), 
cp2=0xbfdc8b67('B')

Expected result:
c1='F'
c2='B'

$ gcc --version
gcc (Debian 4.4.5-5) 4.4.5
$ gfortran --version
GNU Fortran (Debian 4.4.5-5) 4.4.5


/Jörgen
0
Reply teg 11/1/2010 1:03:48 PM

On 11/1/2010 6:03 AM, teg wrote:
> (question forwarded from from gnu.gcc.help)
>
> Hi,
>
> hope someone can explain what happens in the code below.
> I expected the two different pointers cp1 and cp2 to stay different, but
> after the fortran function they point to the same adress. Is that correct?
> With a similar fortran main program there is no mixup.
>
> $ cat f.f
>        function fcall_1(cin)
>        implicit none
>        character cin,fcall_1
>        character cout
>        cout='B'
>        fcall_1=cout
>        return
>        end
>
> $ cat c.c
> #include<stdlib.h>
> #include<stdio.h>
>
> unsigned char * fcall_1_(unsigned char *);
>
> int main(void)
> {
>    unsigned char c1,c2,*cp1,*cp2;
>
>    c1='F';cp1=&c1;
>    c2='A';cp2=&c2;
>    printf("Printing from c before fortran call:\tcp1=%p('%c'), cp2=%p('%c')
> \n",cp1,c1,cp2,c2);
>    cp2=fcall_1_(cp1);
>    c2=*cp2;
>    printf("Printing from c after fortran call:\tcp1=%p('%c'), cp2=%p('%c')
> \n",cp1,c1,cp2,c2);
>
>    return 0;
> }
> $ ./cf.out
> Printing from c before fortran call:	cp1=0xbfdc8b67('F'),
> cp2=0xbfdc8b66('A')
> Printing from c after fortran call:	cp1=0xbfdc8b67('B'),
> cp2=0xbfdc8b67('B')
>
> Expected result:
> c1='F'
> c2='B'

As you don't use the iso_c_binding facility, it's hard to understand how 
you could have an expectation on how this might be handled (necessarily 
differing among compilers).

-- 
Tim Prince
0
Reply Tim 11/1/2010 1:26:50 PM


teg wrote:

> (question forwarded from from gnu.gcc.help)
> 
> Hi,
> 
> hope someone can explain what happens in the code below.
> I expected the two different pointers cp1 and cp2 to stay different, but
> after the fortran function they point to the same adress. Is that correct?
> With a similar fortran main program there is no mixup.
> 
> $ cat f.f
>       function fcall_1(cin)
>       implicit none
>       character cin,fcall_1
>       character cout
>       cout='B'
>       fcall_1=cout
>       return
>       end
> 
> $ cat c.c
> #include <stdlib.h>
> #include <stdio.h>
> 
> unsigned char * fcall_1_(unsigned char *);
> 
> int main(void)
> {
>   unsigned char c1,c2,*cp1,*cp2;
> 
>   c1='F';cp1=&c1;
>   c2='A';cp2=&c2;
>   printf("Printing from c before fortran call:\tcp1=%p('%c'), cp2=%p('%c')
> \n",cp1,c1,cp2,c2);
>   cp2=fcall_1_(cp1);
>   c2=*cp2;
>   printf("Printing from c after fortran call:\tcp1=%p('%c'), cp2=%p('%c')
> \n",cp1,c1,cp2,c2);
> 
>   return 0;
> }
> $ ./cf.out
> Printing from c before fortran call:	cp1=0xbfdc8b67('F'),
> cp2=0xbfdc8b66('A')
> Printing from c after fortran call:	cp1=0xbfdc8b67('B'),
> cp2=0xbfdc8b67('B')
> 
> Expected result:
> c1='F'
> c2='B'
> 
> $ gcc --version
> gcc (Debian 4.4.5-5) 4.4.5
> $ gfortran --version
> GNU Fortran (Debian 4.4.5-5) 4.4.5
> 
> 
> /Jörgen

They are two troubles in your example :
- the signature of fcall_1 is clearly wrong because the FORTRAN routine does 
not return any pointer.
- returning characters, especially insigned ones, involves troubles. I don't 
know excatly why by I observed that in the past. Even if you use the 
iso_c_binding as suggested by Tim Prince you could get trouble.

Your programming may be slightly modified to work with GCC :

- Fortran routine

      function fcall_1(cin)
      implicit none
      character cin
      integer fcall_1
      character cout
      cout='B'
      fcall_1=ichar(cout)
      return
      end

- C main program

#include <stdlib.h>
#include <stdio.h>

int fcall_1_(char *);

int main(void)
{
  unsigned char c1,c2,*cp1,*cp2;

  c1='F';cp1=&c1;
  c2='A';cp2=&c2;
  printf("Printing from c before fortran call:\tcp1=%p('%c'), 
cp2=%p('%c')\n",cp1,c1,cp2,c2);
  c2=fcall_1_(cp1);
  printf("Printing from c after fortran call:\tcp1=%p('%c'), 
cp2=%p('%c')\n",cp1,c1,cp2,c2);

  return 0;
}

Using the iso_c_binding, it becomes :

- fortran routine

      function fcall_1(cin) bind(c,name="fcall_1") result(r)
      use iso_c_binding
      implicit none
      character(c_char),intent(in) :: cin
      integer(c_int) :: r
      r=ICHAR('B')
      end

- C main program :

#include <stdlib.h>
#include <stdio.h>

int fcall_1(char *);

int main(void)
{
  unsigned char c1,c2,*cp1,*cp2;

  c1='F';cp1=&c1;
  c2='A';cp2=&c2;
  printf("Printing from c before fortran call:\tcp1=%p('%c'), 
cp2=%p('%c')\n",cp1,c1,cp2,c2);
  c2=fcall_1(cp1);
  printf("Printing from c after fortran call:\tcp1=%p('%c'), 
cp2=%p('%c')\n",cp1,c1,cp2,c2);

  return 0;
}


François Jacq
0
Reply fj 11/1/2010 2:45:04 PM

"teg" <jteg68@gmail.com> wrote in message 
news:iamdrk$889$1@news.eternal-september.org...

> (question forwarded from from gnu.gcc.help)

> hope someone can explain what happens in the code below.
> I expected the two different pointers cp1 and cp2 to stay different, but
> after the fortran function they point to the same adress. Is that correct?
> With a similar fortran main program there is no mixup.

> $ cat f.f
>      function fcall_1(cin)
>      implicit none
>      character cin,fcall_1
>      character cout
>      cout='B'
>      fcall_1=cout
>      return
>      end

> $ cat c.c
> #include <stdlib.h>
> #include <stdio.h>

> unsigned char * fcall_1_(unsigned char *);

This is a complete misapprehension of what the Fortran function does.
Fortran has an interface called assumed length.  This means that you
can have a subroutine such as

subroutine sub(x)
   character(*) x
   ...
end subroutine sub

Here, dummy argument x to subroutine sub assumes its length from
the actual argument it will be associated with.  The interface
will be something like:

void sub_(char *x_address, int x_len)
{
   ...
}

Notice that since this goes back to F77 where there was no way
to communicate explicit interfaces, that length had to be
passed even if the subroutine knew that it was fixed at length
1 because there was no way to tell the calling program unit
that so it would always pass its length regardless.

Now, for functions that return a character variable, there
is also the possibility of declare a function to have an
assumed length result.  Even though this is not nearly as
useful as assumed length dummies, the caller again couldn't
know whether it was invoking a function with predetermined
length or an assumed length result function, also since this
goes back to F77 that didn't have any capacity for dynamic
memory, the caller had to provide storage for the result.
Thus every function that with character result must receive
also the address and length of its result variable.

To see where this goes for a given compiler, you have to
either read the documentation (zzzz...) or view a disassembly
of compiler output ( :) ).

C:\gfortran\clf\char_c>type char1.f90
function char1(x)
   character*(*) char1, x
   char1 = x
end function char1

C:\gfortran\clf\char_c>gfortran -fomit-frame-pointer -S char1.f90

C:\gfortran\clf\char_c>type char1.s
        .file   "char1.f90"
        .text
..globl char1_
        .def    char1_; .scl    2;      .type   32;     .endef
char1_:
        pushq   %rsi
        pushq   %rbx
        subq    $40, %rsp
        movq    %rcx, 64(%rsp)
        movl    %edx, 72(%rsp)
        movq    %r8, 80(%rsp)
        movl    %r9d, 88(%rsp)
        movl    88(%rsp), %esi
        movl    72(%rsp), %ebx
        testl   %ebx, %ebx
        jle     .L1
        cmpl    %ebx, %esi
        jl      .L3
        movslq  %ebx, %rdx
        movq    80(%rsp), %rax
        movq    %rdx, %r8
        movq    %rax, %rdx
        movq    64(%rsp), %rcx
        call    memmove
        jmp     .L1
..L3:
        movslq  %esi, %rdx
        movq    80(%rsp), %rax
        movq    %rdx, %r8
        movq    %rax, %rdx
        movq    64(%rsp), %rcx
        call    memmove
        movslq  %ebx, %rdx
        movslq  %esi, %rax
        subq    %rax, %rdx
        movslq  %esi, %rax
        addq    64(%rsp), %rax
        movq    %rdx, %r8
        movl    $32, %edx
        movq    %rax, %rcx
        call    memset
..L1:
        addq    $40, %rsp
        popq    %rbx
        popq    %rsi
        ret
        .def    memmove;        .scl    2;      .type   32;     .endef
        .def    memset; .scl    2;      .type   32;     .endef

Now we can see from reading the goat's entrails above that the
arguments in order are:

%rcx result address
%edx result length
%r8  dummy address
%r9d dummy length

Accordingly the C function corresponding to your Fortran function
should be something like:

char *fcall_1_(char *result_address, int result_len,
             char* cin_address, int cin_len)
{
   char cout;
   cout = 'B';
   if(result_len > 0)
   {
      *result_address = cout;
      for(i = 1; i < result_len; i++)
      {
         result_address[i] = ' ';
      }
   }
   return result_address;
}

Mmmm... actually gfortran doesn't seem to return a pointer to the
result, although I think it should do so according to the Win32
API, so fcall_1_ should return void rather than char*.

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply James 11/1/2010 6:22:41 PM

> Mmmm... actually gfortran doesn't seem to return a pointer to the
> result, although I think it should do so according to the Win32 API, so
> fcall_1_ should return void rather than char*.

I disagree with your "it should [return a pointer to the result]
according to the Win32 API". The API doesn't have anything to say about
the way Fortran procedures are translated into machine code.

-- 
FX
0
Reply FX 11/1/2010 7:25:25 PM

On Nov 1, 7:22=A0pm, "James Van Buskirk" <not_va...@comcast.net> wrote:
> "teg" <jte...@gmail.com> wrote in message

> To see where this goes for a given compiler, you have to
> either read the documentation (zzzz...) or view a disassembly
> of compiler output ( :) ).

....in the case of gcc, goat's entrails are unnecessary!

[pault@localhost allocate]# gcc -fdump-tree-original /tmp/tf.f90 /tmp/
tc.c
[pault@localhost allocate]# cat tf*nal
fcall_1 (cin, _cin)
{
  character(kind=3D1) cout[1:1];
  integer(kind=3D4) __result_fcall_1;

  cout[1]{lb: 1 sz: 1} =3D 66;
  __result_fcall_1 =3D (integer(kind=3D4)) cout[1]{lb: 1 sz: 1};
  goto __return_fcall_1;
  __return_fcall_1:;
  return __result_fcall_1;
}


[pault@localhost allocate]# cat tc*nal

;; Function main (main)
;; enabled by -tree-original


{
  unsigned char c1;
  unsigned char c2;
  unsigned char * cp1;
  unsigned char * cp2;

    unsigned char c1;
    unsigned char c2;
    unsigned char * cp1;
    unsigned char * cp2;
  c1 =3D 70;
  cp1 =3D &c1;
  c2 =3D 65;
  cp2 =3D &c2;
  printf ((const char * restrict) (char *) "Printing from c before
fortran call:\tcp1=3D%p(\'%c\'), cp2=3D%p(\'%c\')\n", cp1, (int) c1, cp2,
(int) c2);
  c2 =3D (unsigned char) fcall_1_ ((char *) cp1);
  printf ((const char * restrict) (char *) "Printing from c after
fortran call:\tcp1=3D%p(\'%c\'), cp2=3D%p(\'%c\')\n", cp1, (int) c1, cp2,
(int) c2);
  return 0;
}

Cheers

Paul
0
Reply Paul 11/1/2010 8:10:34 PM

On 2/11/2010 1:45 AM, fj wrote:
....
> - returning characters, especially insigned ones, involves troubles. I don't
> know excatly why by I observed that in the past. Even if you use the
> iso_c_binding as suggested by Tim Prince you could get trouble.
....
Could you elaborate?  I've absolutely no idea what the OP's code was 
trying to demonstrate or do, but returning a single character from a 
function should be robust in the absence of compiler bugs.
....
> Using the iso_c_binding, it becomes :
>
> - fortran routine
>
>        function fcall_1(cin) bind(c,name="fcall_1") result(r)
>        use iso_c_binding
>        implicit none

         character(kind=c_char), intent(in) :: cin

>        integer(c_int) :: r
>        r=ICHAR('B')
>        end

If the OP really, really, really wants to return a pointer, then he 
should write a fortran function that returns a C_PTR.  But then he needs 
to really, really, really think about the lifetime of the thing that 
might be being pointed to.
0
Reply Ian 11/1/2010 9:53:02 PM

Ian Harvey wrote:

> On 2/11/2010 1:45 AM, fj wrote:
> ...
>> - returning characters, especially insigned ones, involves troubles. I
>> don't know excatly why by I observed that in the past. Even if you use
>> the iso_c_binding as suggested by Tim Prince you could get trouble.
> ...
> Could you elaborate?  I've absolutely no idea what the OP's code was
> trying to demonstrate or do, but returning a single character from a
> function should be robust in the absence of compiler bugs.

It should be robust but I think that there is a misunderstanding between 
gfortran character functions and gcc char functions. This is why my fortran 
functions return an int when I want to use them in a C program. This trick 
avoids trouble.

Example of FORTRAN character function :
=====================================

      function fcall_1(cin) result(r)
      implicit none
      character,intent(in) :: cin
      character :: r
      r='B'
      end

Example of C program :
====================

#include <stdlib.h>
#include <stdio.h>
char fcall_1_(char *);
int main(void)
{
  unsigned char c1,c2,*cp1,*cp2;
  c1='F';cp1=&c1;
  c2='A';cp2=&c2;
  printf("Printing from c before fortran call:\tcp1=%p('%c'), 
cp2=%p('%c')\n",cp1,c1,cp2,c2);
  c2=fcall_1_(cp1);
  printf("Printing from c after fortran call:\tcp1=%p('%c'), 
cp2=%p('%c')\n",cp1,c1,cp2,c2);
  return 0;
}

Strange result :
==============

Printing from c before fortran call:    cp1=0xbfcbd4b7('F'), 
cp2=0xbfcbd4b6('A')
Printing from c after fortran call:     cp1=0xbfcbd4b7('B'), 
cp2=0xbfcbd4b6('�')

One see that c1 has been surprisingly changed and c2 does not contain the 
expected character 'B'

This wrong behavior disappears with the iso_c_binding :

      function fcall_1(cin) bind(c,name="fcall_1") result(r)
      use iso_c_binding
      implicit none
      character(kind=c_char),intent(in) :: cin
      character(kind=c_char) :: r
      r='B'
      end

#include <stdlib.h>
#include <stdio.h>
char fcall_1(char *);
int main(void)
{
  unsigned char c1,c2,*cp1,*cp2;
  c1='F';cp1=&c1;
  c2='A';cp2=&c2;
  printf("Printing from c before fortran call:\tcp1=%p('%c'), 
cp2=%p('%c')\n",cp1,c1,cp2,c2);
  c2=fcall_1(cp1);
  printf("Printing from c after fortran call:\tcp1=%p('%c'), 
cp2=%p('%c')\n",cp1,c1,cp2,c2);
  return 0;
}

Result which is the expected one :
================================

Printing from c before fortran call:    cp1=0xbf932807('F'), 
cp2=0xbf932806('A')
Printing from c after fortran call:     cp1=0xbf932807('F'), 
cp2=0xbf932806('B')

-- 
François Jacq
0
Reply fj 11/1/2010 10:43:17 PM

Ian Harvey <ian_harvey@bigpond.com> wrote:

> On 2/11/2010 1:45 AM, fj wrote:
> ...
> > - returning characters, especially insigned ones, involves troubles. I don't
> > know excatly why by I observed that in the past. Even if you use the
> > iso_c_binding as suggested by Tim Prince you could get trouble.
> ...
> Could you elaborate?  I've absolutely no idea what the OP's code was 
> trying to demonstrate or do, but returning a single character from a 
> function should be robust in the absence of compiler bugs.

I was wondering about the same thing. Of course, there is certainly the
possibility of compiler bugs, ISO_C_BINDING support being relatively
new, and character stuff involving extra quirks. But the f2003's
requirements do specify how character stuff is supposed to interact. If
it doesn't work that way, that would be a compiler bug and I'd think the
first order of business would be to file a compiler bug report.

One might also be justified in posting warnings about particular
compiler bugs that mught bite people, but I think it of negative value
to just say that "you could get trouble" without being more specific. If
one wants to be that unspecific, I might as well say that you could get
trouble trying to use computers for anything. While true, that doesn't
help much.

Are you talking about some compiler bug? Or maybe warning that not all
compilers fully support f2003 interop? Or are you talking about needing
to correctly understand exactly what the f2003 interop stuff says? Some
of that can be confusing. For example, note that signed and unsigned
char in C correspond to Fortran integer kinds - not characters. That can
be useful to point out. But without more specifics, heck, you can
certainly get trouble in writing complicated workarounds to avoid using
character type if you don't know exactly why you are avoiding it, but
just that someone once had trouble with something.

Pre iso_c_binding is a very different story. The variations in detail
among compilers are part of why the C interop stuff of f2003 was
needed.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 11/1/2010 10:59:51 PM

"FX" <coudert@alussinan.org> wrote in message 
news:ian475$202$1@news.eternal-september.org...

>> Mmmm... actually gfortran doesn't seem to return a pointer to the
>> result, although I think it should do so according to the Win32 API, so
>> fcall_1_ should return void rather than char*.

> I disagree with your "it should [return a pointer to the result]
> according to the Win32 API". The API doesn't have anything to say about
> the way Fortran procedures are translated into machine code.

Disagreements are good: if we always agreed from the start there
would be no point in communicating.  Microsoft has a manual somewhere
that I couldn't find called SWconventions.doc.  Looking at my copy,
it doesn't say that the callee is supposed to return the pointer,
but everywhere else, like:
http://msdn.microsoft.com/en-us/library/7572ztz4(v=VS.80).aspx
or:
http://www.agner.org/optimize/calling_conventions.pdf , table
7, say that you should return a pointer to a structure that is
too big to fit in registers.  As an example,

C:\gfortran\clf\char_c>type struct1.c
struct test
{
   int dud;
   char data[];
};

struct test f(n)
{
   int i;
   struct test result;
   for(i = 0; i < n; i++)
   {
      result.data[i] = 'x';
   }
   return result;
}


C:\gfortran\clf\char_c>gcc -fomit-frame-pointer -S struct1.c

C:\gfortran\clf\char_c>type struct1.s
        .file   "struct1.c"
        .text
..globl f
        .def    f;      .scl    2;      .type   32;     .endef
f:
        subq    $40, %rsp
        movl    %ecx, 48(%rsp)
        movl    $0, 28(%rsp)
        jmp     .L2
..L3:
        movl    28(%rsp), %eax
        cltq
        movb    $120, 4(%rsp,%rax)
        addl    $1, 28(%rsp)
..L2:
        movl    28(%rsp), %eax
        cmpl    48(%rsp), %eax
        jl      .L3
        movl    (%rsp), %eax
        movl    %eax, 16(%rsp)
        movl    $0, %eax
        mov     16(%rsp), %edx
        andl    $4294967295, %edx
        movabsq $-4294967296, %rcx
        andq    %rcx, %rax
        orq     %rdx, %rax
        addq    $40, %rsp
        ret

Where here the function f sets up the result.data array on its
stack (I don't know how the compiler knows it will be no more than
24 bytes, though) and returns a pointer to it in %rax.

A Fortran example:

C:\gfortran\clf\char_c>type struct2.f90
function g(n)
   implicit none
   type t
      sequence
      integer x
      double precision y
      integer z
   end type t
   type(t) g
   integer n

   g%x = n
   g%y = 2*n
   g%z = 3*n
end function g

C:\gfortran\clf\char_c>gfortran -fomit-frame-pointer -S struct2.f90

C:\gfortran\clf\char_c>type struct2.s
        .file   "struct2.f90"
        .text
..globl g_
        .def    g_;     .scl    2;      .type   32;     .endef
g_:
        subq    $40, %rsp
        movq    %rcx, %rax
        movq    %rdx, 56(%rsp)
        movq    56(%rsp), %rdx
        movl    (%rdx), %edx
        movl    %edx, (%rsp)
        movq    56(%rsp), %rdx
        movl    (%rdx), %edx
        addl    %edx, %edx
        cvtsi2sd        %edx, %xmm0
        movsd   %xmm0, 8(%rsp)
        movq    56(%rsp), %rdx
        movl    (%rdx), %ecx
        movl    %ecx, %edx
        addl    %edx, %edx
        addl    %ecx, %edx
        movl    %edx, 16(%rsp)
        movq    (%rsp), %rdx
        movq    %rdx, (%rax)
        movq    8(%rsp), %rdx
        movq    %rdx, 8(%rax)
        movq    16(%rsp), %rdx
        movq    %rdx, 16(%rax)
        addq    $40, %rsp
        ret

Here function g gets the address of its result variable from the
caller in %rcx and returns the same address in %rax, as anyone would
expect.  Now, even in the original example:

C:\gfortran\clf\char_c>type char1.f90
function char1(x)
   character*(*) char1, x
   char1 = x
end function char1

C:\gfortran\clf\char_c>ifort /S char1.f90
Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.1
Build 20061104
Copyright (C) 1985-2006 Intel Corporation.  All rights reserved.


C:\gfortran\clf\char_c>type char1.asm
; -- Machine type EFI2
; mark_description "Intel(R) Fortran Compiler for Intel(R) EM64T-based 
applicati
ons, Version 9.1    Build 20061104 %s";
; mark_description "-Qvc8 -S";
        .686P
        .387
        OPTION DOTNAME
        ASSUME  CS:FLAT,DS:FLAT,SS:FLAT
        INCLUDELIB <ifconsol>
        INCLUDELIB <libifcoremt>
        INCLUDELIB <libifport>
        INCLUDELIB <libmmt>
        INCLUDELIB <LIBCMT>
        INCLUDELIB <libirc>
        INCLUDELIB <OLDNAMES>
        INCLUDELIB <bufferoverflowu>
_TEXT   SEGMENT DWORD PUBLIC FLAT 'CODE'
; -- Begin  CHAR1
; mark_begin;
IF @Version GE 612
  .MMX
  MMWORD TEXTEQU <QWORD>
ENDIF
IF @Version GE 614
  .XMM
  XMMWORD TEXTEQU <OWORD>
ENDIF
       ALIGN     2
        PUBLIC CHAR1
CHAR1   PROC NEAR
; parameter 1: rcx
; parameter 2: rdx
; parameter 3: r8
; parameter 4: r9
$B1$1:                          ; Preds $B1$0
        push      rdi                                           ;1.10
        sub       rsp, 48                                       ;1.10
        mov       rdi, rcx                                      ;1.10
        mov       QWORD PTR [rsp+32], 0                         ;3.4
        mov       rcx, rdi                                      ;3.4
        call      for_cpystr                                    ;3.4
                                ; LOE rbx rbp rsi rdi r12 r13 r14 r15 xmm6 
xmm7
xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15
$B1$2:                          ; Preds $B1$1
        mov       rax, rdi                                      ;1.10
        add       rsp, 48                                       ;4.1
        pop       rdi                                           ;4.1
        ret                                                     ;4.1
        ALIGN     2
                                ; LOE
; mark_end;
CHAR1 ENDP
xdata   SEGMENT
$unwind$CHAR1 DD        020501H
        DD      070015205H
xdata   ENDS
pdata   SEGMENT
$pdata$CHAR1 DD @imagerel($B1$1#)
        DD      @imagerel($B1$2#+9)
        DD      @imagerel($unwind$CHAR1#)
pdata   ENDS
_TEXT   ENDS
_DATA   SEGMENT DWORD PUBLIC FLAT 'DATA'
_DATA   ENDS
; -- End  CHAR1
_DATA   SEGMENT DWORD PUBLIC FLAT 'DATA'
_DATA   ENDS
EXTRN   for_cpystr:PROC
        INCLUDELIB <ifconsol>
        INCLUDELIB <libifcoremt>
        INCLUDELIB <libifport>
        INCLUDELIB <libmmt>
        INCLUDELIB <LIBCMT>
        INCLUDELIB <libirc>
        INCLUDELIB <OLDNAMES>
        INCLUDELIB <bufferoverflowu>
        END

ifort again gets the address of its result string from the caller in
rcx and returns that address in rax.

Of course the counterargument is that the calling convention is only
definitive for C and C++ and that the result variable is not strictly
speaking a structure too large to fit in registers but a character
string.  However a struct too big to fit in registers seems to me to
be the closest match to a string which cannot be guaranteed to have
its length known at compile time.

Really I just wanted to mention this as I considered it to be a
minor deviation from standard calling conventions, but it's not
that big of a deal because nobody ever checks that pointer except
for the O.P. because the caller knows its value, having passed it
to the callee in the first place.  There is a lot of other stuff
that I would consider higher priority than worrying about this.

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply James 11/1/2010 11:38:48 PM

On Nov 2, 9:43=A0am, fj <francois.j...@irsn.fr> wrote:
> Ian Harvey wrote:
> > On 2/11/2010 1:45 AM, fj wrote:
> > ...
> >> - returning characters, especially insigned ones, involves troubles. I
> >> don't know excatly why by I observed that in the past. Even if you use
> >> the iso_c_binding as suggested by Tim Prince you could get trouble.
> > ...
> > Could you elaborate? =A0I've absolutely no idea what the OP's code was
> > trying to demonstrate or do, but returning a single character from a
> > function should be robust in the absence of compiler bugs.
>
> It should be robust but I think that there is a misunderstanding between
> gfortran character functions and gcc char functions. This is why my fortr=
an
> functions return an int when I want to use them in a C program. This tric=
k
> avoids trouble.
>
> Example of FORTRAN character function :
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>
> =A0 =A0 =A0 function fcall_1(cin) result(r)
> =A0 =A0 =A0 implicit none
> =A0 =A0 =A0 character,intent(in) :: cin
> =A0 =A0 =A0 character :: r
> =A0 =A0 =A0 r=3D'B'
> =A0 =A0 =A0 end
>
> Example of C program :
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>
> #include <stdlib.h>
> #include <stdio.h>
> char fcall_1_(char *);
> int main(void)
> {
> =A0 unsigned char c1,c2,*cp1,*cp2;
> =A0 c1=3D'F';cp1=3D&c1;
> =A0 c2=3D'A';cp2=3D&c2;
> =A0 printf("Printing from c before fortran call:\tcp1=3D%p('%c'),
> cp2=3D%p('%c')\n",cp1,c1,cp2,c2);
> =A0 c2=3Dfcall_1_(cp1);
> =A0 printf("Printing from c after fortran call:\tcp1=3D%p('%c'),
> cp2=3D%p('%c')\n",cp1,c1,cp2,c2);
> =A0 return 0;
>
> }
>
> Strange result :
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>
> Printing from c before fortran call: =A0 =A0cp1=3D0xbfcbd4b7('F'),
> cp2=3D0xbfcbd4b6('A')
> Printing from c after fortran call: =A0 =A0 cp1=3D0xbfcbd4b7('B'),
> cp2=3D0xbfcbd4b6(' ')
>
> One see that c1 has been surprisingly changed and c2 does not contain the
> expected character 'B'
>
> This wrong behavior disappears with the iso_c_binding :
>
....

Ok - your expectations without C interoperability are considerably
greater than mine.  I thought you were talking about problems with C
interoperability in use.
0
Reply Ian 11/2/2010 1:20:58 AM

fj <francois.jacq@irsn.fr> wrote:
(snip)

> It should be robust but I think that there is a misunderstanding between 
> gfortran character functions and gcc char functions. This is why my fortran 
> functions return an int when I want to use them in a C program. This trick 
> avoids trouble.
(big snip)

> This wrong behavior disappears with the iso_c_binding :

Without iso_c_binding some things "usually" work, but you can't
be sure in general.  Even with iso_c_binding it is only guaranteed
to work if you use the specified compiler.

Without a prototype, and often even with one, C promotes anything
smaller than (int) up to (int).  That is "usually" true for function
return values, too.  (It depends somewhat on the register sizes
and stack alignment.)  

As previously mentioned, Fortran CHARACTER sometimes work in unusual
ways, which will cause problems if you don't know those ways.

-- glen
0
Reply glen 11/2/2010 2:26:58 AM

Ian Harvey wrote:

> On Nov 2, 9:43 am, fj <francois.j...@irsn.fr> wrote:
>> Ian Harvey wrote:
>> > On 2/11/2010 1:45 AM, fj wrote:
>> > ...
>> >> - returning characters, especially insigned ones, involves troubles. I
>> >> don't know excatly why by I observed that in the past. Even if you use
>> >> the iso_c_binding as suggested by Tim Prince you could get trouble.
>> > ...
>> > Could you elaborate?  I've absolutely no idea what the OP's code was
>> > trying to demonstrate or do, but returning a single character from a
>> > function should be robust in the absence of compiler bugs.
>>
>> It should be robust but I think that there is a misunderstanding between
>> gfortran character functions and gcc char functions. This is why my
>> fortran functions return an int when I want to use them in a C program.
>> This trick avoids trouble.
>>
>> Example of FORTRAN character function :
>> =====================================
>>
>> function fcall_1(cin) result(r)
>> implicit none
>> character,intent(in) :: cin
>> character :: r
>> r='B'
>> end
>>
>> Example of C program :
>> ====================
>>
>> #include <stdlib.h>
>> #include <stdio.h>
>> char fcall_1_(char *);
>> int main(void)
>> {
>> unsigned char c1,c2,*cp1,*cp2;
>> c1='F';cp1=&c1;
>> c2='A';cp2=&c2;
>> printf("Printing from c before fortran call:\tcp1=%p('%c'),
>> cp2=%p('%c')\n",cp1,c1,cp2,c2);
>> c2=fcall_1_(cp1);
>> printf("Printing from c after fortran call:\tcp1=%p('%c'),
>> cp2=%p('%c')\n",cp1,c1,cp2,c2);
>> return 0;
>>
>> }
>>
>> Strange result :
>> ==============
>>
>> Printing from c before fortran call:    cp1=0xbfcbd4b7('F'),
>> cp2=0xbfcbd4b6('A')
>> Printing from c after fortran call:     cp1=0xbfcbd4b7('B'),
>> cp2=0xbfcbd4b6(' ')
>>
>> One see that c1 has been surprisingly changed and c2 does not contain the
>> expected character 'B'
>>
>> This wrong behavior disappears with the iso_c_binding :
>>
> ...
> 
> Ok - your expectations without C interoperability are considerably
> greater than mine.  I thought you were talking about problems with C
> interoperability in use.

With early versions of gfortran accepting the iso_c_binding, character 
functions were not managed correctly for the same reason. 

I remember this well because I spent a considerable amount of time to 
understand why a certain program did not work... As the OP mentioned 
explicitly gcc+gfortran, I just wanted to suggest a trick in case of strange 
results.

I apologize because the version gcc-4.4.5 already contains the correction of 
that compiler bug.

But because of that bad souvenir, I continue to avoid character functions 
when C binding is involved...

-- 
François Jacq
0
Reply fj 11/2/2010 4:57:02 AM

> However a struct too big to fit in registers seems to me to be the
> closest match to a string which cannot be guaranteed to have its length
> known at compile time.

Again, I don't agree. One is a fixed-size structure, the other is
represented by a pointer and a length. Very different things!

If the API is wrong, you can write a standard-conforming code that
doesn't behave as mandated. I'd be happy to see that :)

-- 
FX
0
Reply FX 11/2/2010 12:06:05 PM

FX <coudert@alussinan.org> wrote:
>> However a struct too big to fit in registers seems to me to be the
>> closest match to a string which cannot be guaranteed to have its length
>> known at compile time.
 
> Again, I don't agree. One is a fixed-size structure, the other is
> represented by a pointer and a length. Very different things!

It is usual in calling convention when the return value is larger
than one or two registers to have the caller pass the address
(with or without length) of a buffer for the callee to store the
result in.  It may even happen for a C struct that is small enough.
(I know it better for C, but it is likely similar for Fortran.)

Allowing for two registers allows double precision (where two
registers are used) or complex values to be returned in registers.
 
> If the API is wrong, you can write a standard-conforming code that
> doesn't behave as mandated. I'd be happy to see that :)

-- glen
0
Reply glen 11/2/2010 7:02:44 PM

"FX" <coudert@alussinan.org> wrote in message 
news:iaourd$d8i$1@news.eternal-september.org...

>> However a struct too big to fit in registers seems to me to be the
>> closest match to a string which cannot be guaranteed to have its length
>> known at compile time.

> Again, I don't agree. One is a fixed-size structure, the other is
> represented by a pointer and a length. Very different things!

> If the API is wrong, you can write a standard-conforming code that
> doesn't behave as mandated. I'd be happy to see that :)

You know, after walking home from the polling place today, my leg,
which I hurt last month, felt too sore for Exercise Period.  My loss
is your gain, however:

C:\gfortran\clf\char_std>type char_std.f90
program char_std
   use ISO_C_BINDING
   implicit none
   interface
      function f(result_address, result_len, dummy_address, dummy_len) &
               bind(C,name='f_')
         use ISO_C_BINDING
         implicit none
         character(kind=C_CHAR) result_address(*)
         integer(C_INT), value :: result_len
         character(kind=C_CHAR) dummy_address(*)
         integer(C_INT), value :: dummy_len
         type(C_PTR) f
      end function f
   end interface
   character(6,C_CHAR), target :: actual_arg
   character(4,C_CHAR), target :: result
   type(C_PTR) cptr_result
   character(kind=C_CHAR), pointer :: fptr_result(:)
   character(80) fmt

   actual_arg = 'qwerty'
   write(*,'(a,z0)') 'result_address = ', &
      transfer(C_LOC(result(1:1)),0_C_INTPTR_T)
   write(*,'(a,z0)') 'dummy_address = ', &
      transfer(C_LOC(actual_arg(1:1)),0_C_INTPTR_T)
   cptr_result = f(result, len(result), actual_arg, len(actual_arg))
   write(*,'(a,z0)') 'cptr_result = ', transfer(cptr_result,0_C_INTPTR_T)
   write(*,'(a)') trim(merge('cptr_result is associated    ', &
      'cptr_result is NOT associated',C_ASSOCIATED(cptr_result)))
   call C_F_POINTER(cptr_result, fptr_result, [len(result)])
   write(*,'(a)') 'Survived call to C_F_POINTER'
   write(fmt,'(a,i0,a)') '(a,',size(fptr_result),'a1)'
   write(*,fmt) 'fptr_result = ', fptr_result
end program char_std

function f(x)
   use ISO_C_BINDING
   implicit none
!DEC$ ATTRIBUTES ALIAS:'f_' :: f
   character(*,C_CHAR) f
   character(*,C_CHAR) x
   integer i
   integer f_lo, f_hi

   f = x
   do i = 1, min(len(f),len(x))
      f_hi = iand(iachar(f(i:i)),NOT(15))
      f_lo = iand(iachar(f(i:i)),15)
      f_lo = iand(f_lo+1,15)
      f(i:i) = achar(ior(f_hi,f_lo))
   end do
end function f

C:\gfortran\clf\char_std>gfortran -std=f2003 char_std.f90 -ochar_std
char_std.f90:37:

function f(x)
1
Warning: Obsolescent feature: CHARACTER(*) function 'f' at (1)

C:\gfortran\clf\char_std>char_std
result_address = 22FDC0
dummy_address = 22FE60
cptr_result = 4
cptr_result is associated
Survived call to C_F_POINTER

All standard as far as gfortran can tell.  It is designed to work
with ifort, but I haven't a recent enough version for this.  Maybe
someone else can check.

Hope you are indeed happy.

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply James 11/2/2010 7:30:57 PM

In article <iapn8k$15l$2@news.eternal-september.org>,
glen herrmannsfeldt  <gah@ugcs.caltech.edu> wrote:
>FX <coudert@alussinan.org> wrote:
>>> However a struct too big to fit in registers seems to me to be the
>>> closest match to a string which cannot be guaranteed to have its length
>>> known at compile time.
> 
>> Again, I don't agree. One is a fixed-size structure, the other is
>> represented by a pointer and a length. Very different things!
>
>It is usual in calling convention when the return value is larger
>than one or two registers to have the caller pass the address
>(with or without length) of a buffer for the callee to store the
>result in.  It may even happen for a C struct that is small enough.
>(I know it better for C, but it is likely similar for Fortran.)

"Usual" is a bit strong.  There are lots of other conventions.


Regards,
Nick Maclaren.
0
Reply nmm1 11/2/2010 7:51:01 PM

On 3/11/2010 8:30 a.m., James Van Buskirk wrote:
> "FX"<coudert@alussinan.org>  wrote in message
> news:iaourd$d8i$1@news.eternal-september.org...
>
>>> However a struct too big to fit in registers seems to me to be the
>>> closest match to a string which cannot be guaranteed to have its length
>>> known at compile time.
>
>> Again, I don't agree. One is a fixed-size structure, the other is
>> represented by a pointer and a length. Very different things!
>
>> If the API is wrong, you can write a standard-conforming code that
>> doesn't behave as mandated. I'd be happy to see that :)
>
> You know, after walking home from the polling place today, my leg,
> which I hurt last month, felt too sore for Exercise Period.

You must be in the US.  Commiserations!
0
Reply Gib 11/3/2010 1:46:27 AM

> All standard as far as gfortran can tell.

Because it's not clever enough, but it sure is not standard code. You're
calling your function f with a different interface than what it is really
declared as.

And yes, I understand why you expect it to work, but it surely is not
standard conforming.

-- 
FX
0
Reply FX 11/3/2010 8:39:59 AM

"James Van Buskirk" <not_valid@comcast.net> wrote in message 
news:iapotn$ac3$1@news.eternal-september.org...
> "FX" <coudert@alussinan.org> wrote in message 
> news:iaourd$d8i$1@news.eternal-september.org...
>
>
> C:\gfortran\clf\char_std>type char_std.f90
> program char_std
>   use ISO_C_BINDING
>   implicit none
>   interface
>      function f(result_address, result_len, dummy_address, dummy_len) &
>               bind(C,name='f_')
>         use ISO_C_BINDING
>         implicit none
>         character(kind=C_CHAR) result_address(*)
>         integer(C_INT), value :: result_len
>         character(kind=C_CHAR) dummy_address(*)
>         integer(C_INT), value :: dummy_len
>         type(C_PTR) f
>      end function f
>   end interface
>   character(6,C_CHAR), target :: actual_arg
>   character(4,C_CHAR), target :: result
>   type(C_PTR) cptr_result
>   character(kind=C_CHAR), pointer :: fptr_result(:)
>   character(80) fmt
>
>   actual_arg = 'qwerty'
>   write(*,'(a,z0)') 'result_address = ', &
>      transfer(C_LOC(result(1:1)),0_C_INTPTR_T)
>   write(*,'(a,z0)') 'dummy_address = ', &
>      transfer(C_LOC(actual_arg(1:1)),0_C_INTPTR_T)
>   cptr_result = f(result, len(result), actual_arg, len(actual_arg))
>   write(*,'(a,z0)') 'cptr_result = ', transfer(cptr_result,0_C_INTPTR_T)
>   write(*,'(a)') trim(merge('cptr_result is associated    ', &
>      'cptr_result is NOT associated',C_ASSOCIATED(cptr_result)))
>   call C_F_POINTER(cptr_result, fptr_result, [len(result)])
>   write(*,'(a)') 'Survived call to C_F_POINTER'
>   write(fmt,'(a,i0,a)') '(a,',size(fptr_result),'a1)'
>   write(*,fmt) 'fptr_result = ', fptr_result
> end program char_std
>
> function f(x)
>   use ISO_C_BINDING
>   implicit none
> !DEC$ ATTRIBUTES ALIAS:'f_' :: f
>   character(*,C_CHAR) f
>   character(*,C_CHAR) x
>   integer i
>   integer f_lo, f_hi
>
>   f = x
>   do i = 1, min(len(f),len(x))
>      f_hi = iand(iachar(f(i:i)),NOT(15))
>      f_lo = iand(iachar(f(i:i)),15)
>      f_lo = iand(f_lo+1,15)
>      f(i:i) = achar(ior(f_hi,f_lo))
>   end do
> end function f
>
> C:\gfortran\clf\char_std>gfortran -std=f2003 char_std.f90 -ochar_std
> char_std.f90:37:
>
> function f(x)
> 1
> Warning: Obsolescent feature: CHARACTER(*) function 'f' at (1)
>
> C:\gfortran\clf\char_std>char_std
> result_address = 22FDC0
> dummy_address = 22FE60
> cptr_result = 4
> cptr_result is associated
> Survived call to C_F_POINTER
>
> All standard as far as gfortran can tell.  It is designed to work
> with ifort, but I haven't a recent enough version for this.  Maybe
> someone else can check.
>
> Hope you are indeed happy.
>
> -- 
> write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
> 6.0134700243160014d-154/),(/'x'/)); end
>
>

With Ifort v11.1.065
For some reason I had to change the following line :
!DEC$ ATTRIBUTES ALIAS:'f_' :: f
to
!DEC$ ATTRIBUTES ALIAS:'_f_' :: f
(I was getting unresolved reference to _f_)

output :

result_address = 17FDFE
dummy_address = 17FDF8
cptr_result = 17FDFE
cptr_result is associated
Survived call to C_F_POINTER
forrtl: warning (402): fort: (1): In call to I/O Write routine, an array 
temporary was created for argument #2

Les 

0
Reply Les 11/3/2010 9:01:54 AM

"Les Neilson" <l.neilson@nospam.co.uk> wrote in message 
news:I6-dnY9g4qzAvEzRnZ2dnUVZ7tidnZ2d@eclipse.net.uk...
>
> output :
>
> result_address = 17FDFE
> dummy_address = 17FDF8
> cptr_result = 17FDFE
> cptr_result is associated
> Survived call to C_F_POINTER
> forrtl: warning (402): fort: (1): In call to I/O Write routine, an array 
> temporary was created for argument #2
>

Sorry. Cut and paste missed a line

fptr_result = rxfs


Les 

0
Reply Les 11/3/2010 9:02:55 AM

"Les Neilson" <l.neilson@nospam.co.uk> wrote in message 
news:I6-dnY9g4qzAvEzRnZ2dnUVZ7tidnZ2d@eclipse.net.uk...

> "James Van Buskirk" <not_valid@comcast.net> wrote in message 
> news:iapotn$ac3$1@news.eternal-september.org...

>>      function f(result_address, result_len, dummy_address, dummy_len) &
>>               bind(C,name='f_')

>> function f(x)
>>   use ISO_C_BINDING
>>   implicit none
>> !DEC$ ATTRIBUTES ALIAS:'f_' :: f

> With Ifort v11.1.065
> For some reason I had to change the following line :
> !DEC$ ATTRIBUTES ALIAS:'f_' :: f
> to
> !DEC$ ATTRIBUTES ALIAS:'_f_' :: f
> (I was getting unresolved reference to _f_)

Were you compiling the 32-bit version on Windows?  It seems to me
from http://www.agner.org/optimize/calling_conventions.pdf, table 20
that ifort on 32- or 64-bit Linux or 64-bit Windows should prepend
no underscore.  Only for 32-bit Windows do I expect the above behavior.

> output :

> result_address = 17FDFE
> dummy_address = 17FDF8
> cptr_result = 17FDFE

So far so good: ifort is returning the pointer expected.

> cptr_result is associated
> Survived call to C_F_POINTER
> forrtl: warning (402): fort: (1): In call to I/O Write routine, an array 
> temporary was created for argument #2

Adding the final line of output from your next post:

> fptr_result = rxfs

This is exactly as anticipated (the IBM -> HAL (inverse) transformation).
Thank you very much for taking the time to test my code.

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply James 11/3/2010 5:14:45 PM

"FX" <coudert@alussinan.org> wrote in message 
news:iar74v$59t$1@news.eternal-september.org...

>> All standard as far as gfortran can tell.

> Because it's not clever enough, but it sure is not standard code. You're
> calling your function f with a different interface than what it is really
> declared as.

> And yes, I understand why you expect it to work, but it surely is not
> standard conforming.

This leads me to a question of whether C interop can ever be
standard-conforming.  Obviously if one side of the interface truly
is programmed in C that part doesn't conform to the Fortran
standard.  Thus the more meaningful question to me is whether the
Fortran part on the side of the interface we are programming is
conforming.

If you wrote the external function f(x) and compiled it and put
the object code in a library it should lead to a standard-conforming
program if it were then invoked from a Fortran program.  I don't
consider the code for external function f(x) to then be made
nonconforming if someone got ahold of our library and the puzzlied
out the low-level interface and managed to invoke it correctly from
a C program.

Similarly, if one had access to a assembly-language code for a
function and managed to write an interface using the C interop
features and then assembled the assembly-language code to object
code and linked it to the object code produced by our Fortran
code it doesn't seem to me to make the Fortran part of the code
nonconforming because that's just what the C interop stuff is
supposed to be able to do, I think.

So even though for a Fortran program one has to consider what
all the code put together as a whole does to determine whether
or not you have a conforming program, where C interop is concerned
I believe the you have to decide based on whether the bits on one
side or the other conform in isolation and then decide on whether
the interface chosen of the possibly more than one that Fortran
allows is consistent.  I claim it should be because existing
calling conventions require that a pointer to the result variable
to be passed back to the caller in similar circumstances.  You
may claim that there is no precedent because neither C nor C++
can return the kind of object the a Fortran function with a
character result variable does so there is no similar circumstance.
I don't want to put words in your mouth, but that seems to me to
be the essence of the difference in our opinons.

Again, it would be unusual for a program to attempt to use the
result variable that I claim is there because the program passed
the result variable to the function in the first place, so even
if I am right here, it should be a low priority (as in perhaps
as low as WONTFIX) to actually make gfortran do what I consider to
be the right thing here.

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply James 11/3/2010 5:56:25 PM

James Van Buskirk <not_valid@comcast.net> wrote:
(snip)

> This leads me to a question of whether C interop can ever be
> standard-conforming.  Obviously if one side of the interface truly
> is programmed in C that part doesn't conform to the Fortran
> standard.  Thus the more meaningful question to me is whether the
> Fortran part on the side of the interface we are programming is
> conforming.

I sometimes wonder, too.  Among others, can one reliably call
Fortran from a C main program?  

(big snip)
 
> I claim it should be because existing
> calling conventions require that a pointer to the result variable
> to be passed back to the caller in similar circumstances.  You
> may claim that there is no precedent because neither C nor C++
> can return the kind of object the a Fortran function with a
> character result variable does so there is no similar circumstance.
> I don't want to put words in your mouth, but that seems to me to
> be the essence of the difference in our opinons.

C89 allows for struct valued functions, where the struct can
contain a char array.  The length has to be a compile time
constant, as for all C89 arrays, and as usual for a struct.

In C, a pointer to a struct is supposed to be equivalent to
a pointer to its first member.  That doesn't obviously 
translate to a function return value, but it does seem that
might be close to interoperable with a Fortran function
returning a CHARACTER*n for constant n.
 
> Again, it would be unusual for a program to attempt to use the
> result variable that I claim is there because the program passed
> the result variable to the function in the first place, so even
> if I am right here, it should be a low priority (as in perhaps
> as low as WONTFIX) to actually make gfortran do what I consider to
> be the right thing here.

-- glen
0
Reply glen 11/3/2010 6:47:20 PM

In article <iasann$8mr$1@news.eternal-september.org>,
glen herrmannsfeldt  <gah@ugcs.caltech.edu> wrote:
>James Van Buskirk <not_valid@comcast.net> wrote:
>
>> This leads me to a question of whether C interop can ever be
>> standard-conforming.  Obviously if one side of the interface truly
>> is programmed in C that part doesn't conform to the Fortran
>> standard.  Thus the more meaningful question to me is whether the
>> Fortran part on the side of the interface we are programming is
>> conforming.
>
>I sometimes wonder, too.  Among others, can one reliably call
>Fortran from a C main program?  

No.


Regards,
Nick Maclaren.
0
Reply nmm1 11/3/2010 6:56:53 PM

On 4/11/2010 4:14 AM, James Van Buskirk wrote:
> Were you compiling the 32-bit version on Windows?  It seems to me
> from http://www.agner.org/optimize/calling_conventions.pdf, table 20
> that ifort on 32- or 64-bit Linux or 64-bit Windows should prepend
> no underscore.  Only for 32-bit Windows do I expect the above behavior.

I saw the same behaviour as Les with ifort on Win32.

Doesn't this just prove that getting C and fortran to work together 
without BIND(C) etal is platform dependent?  And since you can't have a 
CHARACTER(*) result with BIND(C), doesn't that prove that pretending 
CHARACTER(*) results are char*'s is platform dependent?
0
Reply Ian 11/3/2010 8:17:46 PM

On 11/3/10 1:56 PM, nmm1@cam.ac.uk wrote:
> In article<iasann$8mr$1@news.eternal-september.org>,
> glen herrmannsfeldt<gah@ugcs.caltech.edu>  wrote:
>> James Van Buskirk<not_valid@comcast.net>  wrote:
>>
>>> This leads me to a question of whether C interop can ever be
>>> standard-conforming.  Obviously if one side of the interface truly
>>> is programmed in C that part doesn't conform to the Fortran
>>> standard.  Thus the more meaningful question to me is whether the
>>> Fortran part on the side of the interface we are programming is
>>> conforming.
>>
>> I sometimes wonder, too.  Among others, can one reliably call
>> Fortran from a C main program?
>
> No.
>
>
> Regards,
> Nick Maclaren.

I don't know, maybe "Yes, No, Maybe" is a better answer for F2003.

IF the Fortran processor has chosen some particular C processor as its 
companion processor, then the call has to work as reliably as any other 
call.  That's the whole purpose of the C interop stuff.  The intro to 
chapter 15 says "a Fortran subprogram can be referenced from a function 
defined by means of C" and then describes the rules for making it work. 
  If the programmer follows the rules, why wouldn't it work?

The practical problem is that the Fortran compiler isn't required to 
have a C companion processor.  It's only required to have a companion 
that understands C prototypes.  It's OK to have a sort-of-C companion 
and then it's processor dependent whether or not any particular call 
would work.  At least, that's the way I'd read the interop stuff.

Dick Hendrickson

0
Reply Dick 11/3/2010 9:51:34 PM

In article <8je3r7FnrtU1@mid.individual.net>,
Dick Hendrickson  <dick.hendrickson@att.net> wrote:
>On 11/3/10 1:56 PM, nmm1@cam.ac.uk wrote:
>> In article<iasann$8mr$1@news.eternal-september.org>,
>> glen herrmannsfeldt<gah@ugcs.caltech.edu>  wrote:
>>>
>>> I sometimes wonder, too.  Among others, can one reliably call
>>> Fortran from a C main program?
>>
>> No.
>
>I don't know, maybe "Yes, No, Maybe" is a better answer for F2003.

I stand by my response, given the word "reliably".

>IF the Fortran processor has chosen some particular C processor as its
>companion processor, then the call has to work as reliably as any other
>call.  That's the whole purpose of the C interop stuff.  The intro to
>chapter 15 says "a Fortran subprogram can be referenced from a function
>defined by means of C" and then describes the rules for making it work.
>  If the programmer follows the rules, why wouldn't it work?

Because it's foul to implement, and few people even understand
the issues; that always was the case, but it's worse than it was.
Almost all implementations that 'support' that use do so well
enough for simple tests to work, but not much further.

Think access to the environment (including the standard units),
memory management, exception handling (in the most general sense),
termination clean-up and so on.

I don't care what the standard says - where realities conflict with
standards, the latter rarely win out without throwing the baby out
with the bathwater.


Regards,
Nick Maclaren.
0
Reply nmm1 11/3/2010 11:35:38 PM

"Ian Harvey" <ian_harvey@bigpond.com> wrote in message 
news:JmjAo.1296$MF5.294@viwinnwfe02.internal.bigpond.com...

> On 4/11/2010 4:14 AM, James Van Buskirk wrote:

>> Were you compiling the 32-bit version on Windows?  It seems to me
>> from http://www.agner.org/optimize/calling_conventions.pdf, table 20
>> that ifort on 32- or 64-bit Linux or 64-bit Windows should prepend
>> no underscore.  Only for 32-bit Windows do I expect the above behavior.

> I saw the same behaviour as Les with ifort on Win32.

Since I feel there is a danger of miscommunication here I am going to
insert a rather tedious remark on nomenclature.  You may observe in
the quoted paragraph I use rather long-winded terms like 32-bit Windows
or 64-bit Linux.  I do this because more abbreviated expressions may
be ambiguous.  For example I used to use 'x64' to describe 64-bit
Windows because it's a registered trademark (as in Windows XP
Professional x64 Edition) but then people started telling me that they
thought that it could mean 64-bit Linux or other operating system
families, like Cellophane.  Win32 is similarly ambiguous in that "Win32
API" is the name for the OS-provided API in both 32-bit and 64-bit
Windows: the name of kernel32.dll doesn't get changed to kernel64.dll,
for example.  But I take it that you mean 32-bit Windows in the above
sentence.

Now, in my paragraph quoted above I was saying that ifort on 64-bit
Windows and both 32-bit and 64-bit Linux should have the line:

!DEC$ ATTRIBUTES ALIAS:'f_' :: f

whereas I expect ifort on 32-bit Windows needs:

!DEC$ ATTRIBUTES ALIAS:'_f_' :: f

and that I concluded that Les was compiling for 32-bit Windows because
he required the latter syntax.  Now I am reading your message to mean
that you also compiled on 32-bit Windows and needed '_f_' rather than
'f_' and got the same output as did Les, is that right?  If so it would
be cool if you could try on any of the 3 other possibilities and let
me know how it went.

I suspect that with the right C binding name in the interface block
and the right switches for each of the eight possibilities of
gfortran/ifort, 32-/64-bit Windows/Linux one could get rid of that
Directive-Enhanced Compilation line entirely but I am not familiar
enough with the switches available on all the compilers to confirm
my suspicion.

> Doesn't this just prove that getting C and fortran to work together 
> without BIND(C) etal is platform dependent?  And since you can't have a 
> CHARACTER(*) result with BIND(C), doesn't that prove that pretending 
> CHARACTER(*) results are char*'s is platform dependent?

There is another set of standards out there besides language
standards.  I'm thinking about the platform ABI.  An example for
64-bit Linux, feel free to knock over any of the cards as I build
my house.

First I think that 64-bit Linux uses the AMD64 ABI as decribed in:

http://www.nasm.us/links/unix64abi

On page 1 it says:

"No attempt has been made to specify an ABI for languages other than
C. However, it is assumed that many programming languages will wish
to link with code written in C, so that the ABI specifications
documented here apply there too."

Then on classifying arguments on page 18 we read:

"The classification of aggregate (structures and arrays) and union
types works as follows:

1. If the size of an object is larger than four eightbytes, or it
contains unaligned fields, it has class MEMORY."

I consider that the result of a CHARACTER(*) FUNCTION can not be
known in general to have any restriction on its size so that it
must be assigned class MEMORY.

And finally on page 22 we find:

"Returning of Values  The returning of values is done according
to the following algorithm:

1. Classify the return type with the classification algorithm.

2. If the type has class MEMORY, then the caller provides space
for the return value and passes the address of this storage in %rdi
as if it were the first argument to the function. In effect, this
address becomes a �hidden� first argument. This storage must not
overlap any data visible to the callee through other names than
this argument.

On return %rax will contain the address that has been passed in by
the caller in %rdi."

So on 64-bit Linux I would consider it an aberration if a pointer
to the result string were not returned in %rax.

Now, in 64-bit Windows we have the x64 Software Conventions
described in:

http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx

And downstream of this we see:

http://msdn.microsoft.com/en-us/library/7572ztz4.aspx

"Return Vaules (C++)

Visual Studio 2010

Return values that can fit into 64-bits are returned through RAX
(including __m64 types), except for __m128, __m128i, __m128d, floats,
and doubles, which are returned in XMM0. If the return value does not
fit within 64 bits, then the caller assumes the responsibility of
allocating and passing a pointer for the return value as the first
argument. Subsequent arguments are then shifted one argument to the
right. That same pointer must be returned by the callee in RAX. User
defined types to be returned must be 1, 2, 4, 8, 16, 32, or 64 bits
in length."

Since the result variable in question again can't be guaranteed to
fit within 64 bits, the caller should pass a pointer to the data
area to be filled with the result variable the the callee should
return that same pointer in RAX.

Now, although C++ is called out as the applicable language here
again it seems logical to me that a Fortran compiler should be
compatible with this convention.  One of the neat things about
64-bit Windows is that there is only one calling convention;
unnecessarily creating a novel convention seems to me to
complicate an environment that should be relatively simple.

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply James 11/4/2010 1:29:47 AM

It is way too early for me and I haven't had my coffee yet. It was early 
yesterday too when I tested your program so forgot to say anything about the 
system setup.
(1)
Windows Vista Ultimate 64bit SP2
Intel Core2 Quad CPU 3Ghz
Ifort V11.1.065 with Visual Studio 2008
Generate interface blocks = no
Check routine interfaces = no
Calling convention = default

(2)
32bit compile/build/run produced the results shown previously.

(3)
x64bit compile produces the following
main.f90(41): warning #7984: A CHARACTER function name must not be declared 
with an asterisk type-param-value (i.e., (LEN=*)) if the function is part of 
an interface-body. No interface block will be generated.   [F]
Linking...
main.obj : error LNK2019: unresolved external symbol f_ referenced in 
function MAIN__
x64\Debug/ivftest.exe : fatal error LNK1120: 1 unresolved externals

(4)
I changed the !DEC$ ATTRIBUTES ALIAS:'_f_' :: f
back to
DEC$ ATTRIBUTES ALIAS:'f_' :: f
(removed the leading underscore)

x64 compile/build/run produces

result_address = 12FE4E
dummy_address = 12FE48
cptr_result = 12FE4E
cptr_result is associated
Survived call to C_F_POINTER
forrtl: warning (402): fort: (1): In call to I/O Write routine, an array 
temporary was created for argument #2

fptr_result = rxfs

Les

"James Van Buskirk" <not_valid@comcast.net> wrote in message 
news:iat2ah$g4j$1@news.eternal-september.org...
> "Ian Harvey" <ian_harvey@bigpond.com> wrote in message 
> news:JmjAo.1296$MF5.294@viwinnwfe02.internal.bigpond.com...
>
>> On 4/11/2010 4:14 AM, James Van Buskirk wrote:
>
>>> Were you compiling the 32-bit version on Windows?  It seems to me
>>> from http://www.agner.org/optimize/calling_conventions.pdf, table 20
>>> that ifort on 32- or 64-bit Linux or 64-bit Windows should prepend
>>> no underscore.  Only for 32-bit Windows do I expect the above behavior.
>
>> I saw the same behaviour as Les with ifort on Win32.
>
> Since I feel there is a danger of miscommunication here I am going to
> insert a rather tedious remark on nomenclature.  You may observe in
> the quoted paragraph I use rather long-winded terms like 32-bit Windows
> or 64-bit Linux.  I do this because more abbreviated expressions may
> be ambiguous.  For example I used to use 'x64' to describe 64-bit
> Windows because it's a registered trademark (as in Windows XP
> Professional x64 Edition) but then people started telling me that they
> thought that it could mean 64-bit Linux or other operating system
> families, like Cellophane.  Win32 is similarly ambiguous in that "Win32
> API" is the name for the OS-provided API in both 32-bit and 64-bit
> Windows: the name of kernel32.dll doesn't get changed to kernel64.dll,
> for example.  But I take it that you mean 32-bit Windows in the above
> sentence.
>
> Now, in my paragraph quoted above I was saying that ifort on 64-bit
> Windows and both 32-bit and 64-bit Linux should have the line:
>
> !DEC$ ATTRIBUTES ALIAS:'f_' :: f
>
> whereas I expect ifort on 32-bit Windows needs:
>
> !DEC$ ATTRIBUTES ALIAS:'_f_' :: f
>
> and that I concluded that Les was compiling for 32-bit Windows because
> he required the latter syntax.  Now I am reading your message to mean
> that you also compiled on 32-bit Windows and needed '_f_' rather than
> 'f_' and got the same output as did Les, is that right?  If so it would
> be cool if you could try on any of the 3 other possibilities and let
> me know how it went.
>
> I suspect that with the right C binding name in the interface block
> and the right switches for each of the eight possibilities of
> gfortran/ifort, 32-/64-bit Windows/Linux one could get rid of that
> Directive-Enhanced Compilation line entirely but I am not familiar
> enough with the switches available on all the compilers to confirm
> my suspicion.
>
>> Doesn't this just prove that getting C and fortran to work together 
>> without BIND(C) etal is platform dependent?  And since you can't have a 
>> CHARACTER(*) result with BIND(C), doesn't that prove that pretending 
>> CHARACTER(*) results are char*'s is platform dependent?
>
> There is another set of standards out there besides language
> standards.  I'm thinking about the platform ABI.  An example for
> 64-bit Linux, feel free to knock over any of the cards as I build
> my house.
>
> First I think that 64-bit Linux uses the AMD64 ABI as decribed in:
>
> http://www.nasm.us/links/unix64abi
>
> On page 1 it says:
>
> "No attempt has been made to specify an ABI for languages other than
> C. However, it is assumed that many programming languages will wish
> to link with code written in C, so that the ABI specifications
> documented here apply there too."
>
> Then on classifying arguments on page 18 we read:
>
> "The classification of aggregate (structures and arrays) and union
> types works as follows:
>
> 1. If the size of an object is larger than four eightbytes, or it
> contains unaligned fields, it has class MEMORY."
>
> I consider that the result of a CHARACTER(*) FUNCTION can not be
> known in general to have any restriction on its size so that it
> must be assigned class MEMORY.
>
> And finally on page 22 we find:
>
> "Returning of Values  The returning of values is done according
> to the following algorithm:
>
> 1. Classify the return type with the classification algorithm.
>
> 2. If the type has class MEMORY, then the caller provides space
> for the return value and passes the address of this storage in %rdi
> as if it were the first argument to the function. In effect, this
> address becomes a "hidden" first argument. This storage must not
> overlap any data visible to the callee through other names than
> this argument.
>
> On return %rax will contain the address that has been passed in by
> the caller in %rdi."
>
> So on 64-bit Linux I would consider it an aberration if a pointer
> to the result string were not returned in %rax.
>
> Now, in 64-bit Windows we have the x64 Software Conventions
> described in:
>
> http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx
>
> And downstream of this we see:
>
> http://msdn.microsoft.com/en-us/library/7572ztz4.aspx
>
> "Return Vaules (C++)
>
> Visual Studio 2010
>
> Return values that can fit into 64-bits are returned through RAX
> (including __m64 types), except for __m128, __m128i, __m128d, floats,
> and doubles, which are returned in XMM0. If the return value does not
> fit within 64 bits, then the caller assumes the responsibility of
> allocating and passing a pointer for the return value as the first
> argument. Subsequent arguments are then shifted one argument to the
> right. That same pointer must be returned by the callee in RAX. User
> defined types to be returned must be 1, 2, 4, 8, 16, 32, or 64 bits
> in length."
>
> Since the result variable in question again can't be guaranteed to
> fit within 64 bits, the caller should pass a pointer to the data
> area to be filled with the result variable the the callee should
> return that same pointer in RAX.
>
> Now, although C++ is called out as the applicable language here
> again it seems logical to me that a Fortran compiler should be
> compatible with this convention.  One of the neat things about
> 64-bit Windows is that there is only one calling convention;
> unnecessarily creating a novel convention seems to me to
> complicate an environment that should be relatively simple.
>
> -- 
> write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
> 6.0134700243160014d-154/),(/'x'/)); end
>
> 

0
Reply Les 11/4/2010 8:25:24 AM

On 4/11/2010 12:29 PM, James Van Buskirk wrote:
> "Ian Harvey"<ian_harvey@bigpond.com>  wrote in message
> news:JmjAo.1296$MF5.294@viwinnwfe02.internal.bigpond.com...
>
>> On 4/11/2010 4:14 AM, James Van Buskirk wrote:
>
>>> Were you compiling the 32-bit version on Windows?  It seems to me
>>> from http://www.agner.org/optimize/calling_conventions.pdf, table 20
>>> that ifort on 32- or 64-bit Linux or 64-bit Windows should prepend
>>> no underscore.  Only for 32-bit Windows do I expect the above behavior.
>
>> I saw the same behaviour as Les with ifort on Win32.
>
> Since I feel there is a danger of miscommunication here I am going to
> insert a rather tedious remark on nomenclature.  You may observe in
> the quoted paragraph I use rather long-winded terms like 32-bit Windows
> or 64-bit Linux.  I do this because more abbreviated expressions may
> be ambiguous.  For example I used to use 'x64' to describe 64-bit
> Windows because it's a registered trademark (as in Windows XP
> Professional x64 Edition) but then people started telling me that they
> thought that it could mean 64-bit Linux or other operating system
> families, like Cellophane.  Win32 is similarly ambiguous in that "Win32
> API" is the name for the OS-provided API in both 32-bit and 64-bit
> Windows: the name of kernel32.dll doesn't get changed to kernel64.dll,
> for example.  But I take it that you mean 32-bit Windows in the above
> sentence.

Yes.  As both build platform and target, with ifort 11.1.067, using 
/check:all /warn:all.

 > Lots...

Sure, and you know much more about all this than I do know (or will 
know, or _want to know_, more to the point), but given Fortran-C interop 
per F2003 is now widely available, I just think that writing the sort of 
code in the original post that relies on _any_ platform ABI is a bit 
dubious, in the absence of some real good reason to the contrary. 
Mainly because next week, next year, next decade, me, you or some other 
poor sod might be compiling that code on a different platform and then 
anything goes.

For example - I note that the particular compiler I regularly use 
(ifort, 11.1.067, on IA-32, on windows, etc) uses cdecl out-of-the-box, 
but other compilers from that "family" on 32-bit windows didn't (they 
used stdcall, which is the 32-bit windows system convention??).  That 
sort of thing can cause lots and lots of fun - as posts in the Intel 
forum over time testify.

In the context of the original post the responses should have been more 
along the line of "WTF are you trying to do, it appears to involve 
Fortran and C - so whatever it is stop now and go and read about 
BIND(C), please understand why the text about CHARACTER(*) function 
results is written in a slightly harder to read font in the standard; 
and while you are at it stop using a source form that dates from the 
time when computers came configured with a stone tablet reader".

And besides, all that !DEC$ stuff scares me, though that could just be 
because the syntax colouring in my editor is a bit too vivid.
0
Reply Ian 11/4/2010 12:24:45 PM

On 11/4/2010 5:24 AM, Ian Harvey wrote:
> On 4/11/2010 12:29 PM, James Van Buskirk wrote:
>> "Ian Harvey"<ian_harvey@bigpond.com> wrote in message
>> news:JmjAo.1296$MF5.294@viwinnwfe02.internal.bigpond.com...

> For example - I note that the particular compiler I regularly use
> (ifort, 11.1.067, on IA-32, on windows, etc) uses cdecl out-of-the-box,
> but other compilers from that "family" on 32-bit windows didn't (they
> used stdcall, which is the 32-bit windows system convention??).

cdecl was the 32-bit Windows convention for C up to 10 years ago. 
Fortran compilers extended it slightly, not all identically. You would 
use it only for historical reasons, and with the intent of making your 
code require porting for any other platform, even the simplest 64-bit 
Windows cases.

>
> And besides, all that !DEC$ stuff scares me, though that could just be
> because the syntax colouring in my editor is a bit too vivid.

It would be used only where the writer wishes to restrict use to certain 
compilers and platforms.  Even the vendors of those compilers don't 
advocate it, except where there is a known advantage to non-portable 
code.  The most common case is with direct calls to Microsoft system 
library functions which perform tasks not covered by Fortran or by 
common supplementary functions provided with Fortran compilers.

-- 
Tim Prince
0
Reply Tim 11/4/2010 12:43:24 PM

"Ian Harvey" <ian_harvey@bigpond.com> wrote in message 
news:gxxAo.1365$gM3.393@viwinnwfe01.internal.bigpond.com...

> On 4/11/2010 12:29 PM, James Van Buskirk wrote:

> > Lots...

> Sure, and you know much more about all this than I do know (or will know, 
> or _want to know_, more to the point), but given Fortran-C interop per 
> F2003 is now widely available, I just think that writing the sort of code 
> in the original post that relies on _any_ platform ABI is a bit dubious, 
> in the absence of some real good reason to the contrary. Mainly because 
> next week, next year, next decade, me, you or some other poor sod might be 
> compiling that code on a different platform and then anything goes.

Good reasons to the contrary can abound.  It is not unusual for
Fortran programmers to want to resolve interface issues by modifying
the Fortran code, preferably using C interop, but C programmers may
want to work with the C code.  For example, they may not even have
the target Fortran compiler available to them, and even if they did it
might mean modifying not only the function in question but also all
program units that invoke it.  It's possible for someone who programs
with great confidence in C to really struggle with Fortran and there
are some questions about the level of indirection of dummy arguments
that can be tricky the first time around.

> For example - I note that the particular compiler I regularly use (ifort, 
> 11.1.067, on IA-32, on windows, etc) uses cdecl out-of-the-box, but other 
> compilers from that "family" on 32-bit windows didn't (they used stdcall, 
> which is the 32-bit windows system convention??).  That sort of thing can 
> cause lots and lots of fun - as posts in the Intel forum over time 
> testify.

ifort can use stdcall if desired.  I think that dvf/cvf perhaps along
with Microsoft's compiler were the only f90 compilers fo use stdcall
as the default.  Life is way simpler in 64-bit Windows where there is
only one calling convention.

> In the context of the original post the responses should have been more 
> along the line of "WTF are you trying to do, it appears to involve Fortran 
> and C - so whatever it is stop now and go and read about BIND(C), please 
> understand why the text about CHARACTER(*) function results is written in 
> a slightly harder to read font in the standard; and while you are at it 
> stop using a source form that dates from the time when computers came 
> configured with a stone tablet reader".

Again, changing the Fortran code may not be an option, so all that
one can do in that case is to help the O.P. to muddle along
somehow.  If you had a CHARACTER(1) function to invoke you could
declare it as:

CHARACTER(1) f

in the calling program unit.  However, this is the same syntax for
declaring a CHARACTER(*) function when the calling program unit
will require a result of length 1.  Since the compiler can't tell
the difference, it must generate the same sequence to invoke
whatever function is really out there.  Thus the CHARACTER(*)
function example is sort of easier to understand because you can
see why all that extra baggage is there in the calling sequence
even for a CHARACTER function of fixed length, even if that length
is 1 or even 0.

> And besides, all that !DEC$ stuff scares me, though that could just be 
> because the syntax colouring in my editor is a bit too vivid.

As explained, this is just to get the name mangling consistent.
There may be a way to do away with that line.  I think a *.DEF file
may be a possible solution, for example.

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply James 11/4/2010 3:48:58 PM

"Les Neilson" <l.neilson@nospam.co.uk> wrote in message 
news:JrGdnejX5b_Q90_RnZ2dnUVZ8rqdnZ2d@eclipse.net.uk...

> (3)
> x64bit compile produces the following
> main.f90(41): warning #7984: A CHARACTER function name must not be 
> declared with an asterisk type-param-value (i.e., (LEN=*)) if the function 
> is part of an interface-body. No interface block will be generated.   [F]


That warning seems to be there because /gen_interfaces (or however it's
spelled) is turned on, so it's benign.

> Linking...
> main.obj : error LNK2019: unresolved external symbol f_ referenced in 
> function MAIN__
> x64\Debug/ivftest.exe : fatal error LNK1120: 1 unresolved externals

> (4)
> I changed the !DEC$ ATTRIBUTES ALIAS:'_f_' :: f
> back to
> DEC$ ATTRIBUTES ALIAS:'f_' :: f
> (removed the leading underscore)

Good.  This is what I expected.

> x64 compile/build/run produces

> result_address = 12FE4E
> dummy_address = 12FE48
> cptr_result = 12FE4E
> cptr_result is associated
> Survived call to C_F_POINTER
> forrtl: warning (402): fort: (1): In call to I/O Write routine, an array 
> temporary was created for argument #2

> fptr_result = rxfs

Looks good.  Thanks.

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply James 11/4/2010 3:52:55 PM

"James Van Buskirk" <not_valid@comcast.net> wrote in message 
news:ias7of$7jb$1@news.eternal-september.org...

[Comment about whether a gfortran character function should return
a pointer to the result variable]

> Again, it would be unusual for a program to attempt to use the
> result variable that I claim is there because the program passed
> the result variable to the function in the first place, so even
> if I am right here, it should be a low priority (as in perhaps
> as low as WONTFIX) to actually make gfortran do what I consider to
> be the right thing here.

OK, now I have found out more about what's going on.  Look at
this example compiled in 32-bit gcc:

C:\gfortran\clf\mxcsr>type test1.c
struct T
{
   int a;
   int b;
   int c;
   int d;
};

struct T _cdecl f(int x,int y)
{
   struct T result;

   result.a = x;
   result.b = y;
   result.c = 0;
   result.d = 0;

   return result;
}

C:\gfortran\clf\mxcsr>gcc -S test1.c

C:\gfortran\clf\mxcsr>type test1.s
        .file   "test1.c"
        .text
..globl _f
        .def    _f;     .scl    2;      .type   32;     .endef
_f:
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %edi
        pushl   %esi
        pushl   %ebx
        subl    $16, %esp
        movl    12(%ebp), %eax
        movl    %eax, -28(%ebp)
        movl    16(%ebp), %eax
        movl    %eax, -24(%ebp)
        movl    $0, -20(%ebp)
        movl    $0, -16(%ebp)
        movl    8(%ebp), %edx
        leal    -28(%ebp), %ebx
        movl    $4, %eax
        movl    %edx, %edi
        movl    %ebx, %esi
        movl    %eax, %ecx
        rep movsl
        movl    8(%ebp), %eax
        addl    $16, %esp
        popl    %ebx
        popl    %esi
        popl    %edi
        leave
        ret     $4

Here gcc not only returns the result pointer in %eax, but pops
the result pointer off the stack!  gfortran generates identical
code for the following:

C:\gfortran\clf\mxcsr>type test2.f90
function test2(x,y) bind(C)
   use ISO_C_BINDING
   implicit none
   type, bind(C) :: T
      integer(C_INT) a
      integer(C_INT) b
      integer(C_INT) c
      integer(C_INT) d
   end type T
   type(T) test2
   integer(C_INT), value :: x
   integer(C_INT), value :: y

   test2%a = x
   test2%b = y
   test2%c = 0
   test2%d = 0
end function test2

C:\gfortran\clf\mxcsr>gfortran -S test2.f90

C:\gfortran\clf\mxcsr>type test2.s
        .file   "test2.f90"
        .text
..globl _test2
        .def    _test2; .scl    2;      .type   32;     .endef
_test2:
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %edi
        pushl   %esi
        pushl   %ebx
        subl    $16, %esp
        movl    12(%ebp), %eax
        movl    %eax, -28(%ebp)
        movl    16(%ebp), %eax
        movl    %eax, -24(%ebp)
        movl    $0, -20(%ebp)
        movl    $0, -16(%ebp)
        movl    8(%ebp), %edx
        leal    -28(%ebp), %ebx
        movl    $4, %eax
        movl    %edx, %edi
        movl    %ebx, %esi
        movl    %eax, %ecx
        rep movsl
        movl    8(%ebp), %eax
        addl    $16, %esp
        popl    %ebx
        popl    %esi
        popl    %edi
        leave
        ret     $4

Identical down to returning the result pointer in %eax and
popping it off the stack!  But when Microsoft compiles the
code:

C:\gfortran\clf\mxcsr>cl /c /Fa test1.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.363 for 
80x86

Copyright (C) Microsoft Corporation.  All rights reserved.

test1.c

C:\gfortran\clf\mxcsr>type test1.asm
; Listing generated by Microsoft (R) Optimizing Compiler Version 
14.00.50727.363


        TITLE   C:\gfortran\clf\mxcsr\test1.c
        .686P
        .XMM
        include listing.inc
        .model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  _f
; Function compile flags: /Odtp
_TEXT   SEGMENT
_result$ = -16                                          ; size = 16
$T621 = 8                                               ; size = 4
_x$ = 12                                                ; size = 4
_y$ = 16                                                ; size = 4
_f      PROC
; File c:\gfortran\clf\mxcsr\test1.c
; Line 10
        push    ebp
        mov     ebp, esp
        sub     esp, 16                                 ; 00000010H
; Line 13
        mov     eax, DWORD PTR _x$[ebp]
        mov     DWORD PTR _result$[ebp], eax
; Line 14
        mov     ecx, DWORD PTR _y$[ebp]
        mov     DWORD PTR _result$[ebp+4], ecx
; Line 15
        mov     DWORD PTR _result$[ebp+8], 0
; Line 16
        mov     DWORD PTR _result$[ebp+12], 0
; Line 18
        mov     edx, DWORD PTR $T621[ebp]
        mov     eax, DWORD PTR _result$[ebp]
        mov     DWORD PTR [edx], eax
        mov     ecx, DWORD PTR _result$[ebp+4]
        mov     DWORD PTR [edx+4], ecx
        mov     eax, DWORD PTR _result$[ebp+8]
        mov     DWORD PTR [edx+8], eax
        mov     ecx, DWORD PTR _result$[ebp+12]
        mov     DWORD PTR [edx+12], ecx
        mov     eax, DWORD PTR $T621[ebp]
; Line 19
        mov     esp, ebp
        pop     ebp
        ret     0
_f      ENDP
_TEXT   ENDS
END

Again cl returns the result pointer in eax, but doesn't pop
it off the stack!  In:

http://www.agner.org/optimize/calling_conventions.pdf

I couldn't find any mention of the result pointer getting
popped off the stack, but in:

http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl

"There are some variations in the interpretation of cdecl,
particularly in how to return values. As a result, x86 programs
compiled for different operating system platforms and/or by
different compilers can be incompatible, even if they both use the
"cdecl" convention and do not call out to the underlying
environment."

"To pass "in memory", the caller allocates memory and passes a
pointer to it as a hidden first parameter; the callee populates the
memory and returns the pointer, popping the hidden pointer when
returning."

So the author of this page does mention the result pointer getting
cleaned up off the stack.  Given that there is no agreement
between cl and gcc as to whether the result pointer should be
popped, and that this can corrupt the stack and cause the program
to fault, there is just no point in pursuing a minor issue as to
whether Fortran functions that return character results are
conforming to the platform ABI.  It seems that no two compilers
are in agreement at this level of detail anyhow, and since that
has no chance of changing...

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply James 11/13/2010 3:15:19 AM

34 Replies
782 Views

(page loaded in 0.739 seconds)

Similiar Articles:


















7/20/2012 1:31:46 PM


Reply: