(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)
|