Re: Win32 API and gfortran



"Steve Lionel" <steve.lionel@xxxxxxxxx> wrote in message
news:1194963380.320316.54440@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

On Nov 13, 1:07 am, "James Van Buskirk" <not_va...@xxxxxxxxxxx> wrote:

Cool. I see that you are using the /iface:stdref switch whereas in
my search I stopped when I saw the /iface:stdcall switch only. It
does look like /iface:stdref is more consistent with Fortran norms,
but in the case of BIND(C) procedures everything is specified in
the interface so for these procedures the two switches should be
indistinguishable, am I right? The reason I ask is because one could
write out a module containing only interface blocks and compile the
module with a switch -mrtd -magic-names :) or /iface:stdcall and then
any program unit that USEs the module would know to call procedures
whose interfaces were described in that module to use STDCALL and
mangle the names, even if it were itself compiled with /iface:default,
right?

Here you're stepping into quicksand. The Intel compiler's view is
that the /iface switches and ATTRIBUTES directives change the compiler
default behavior in ways that can be overridden by other explicit
syntax. For example, if you had used /iface:stdref and the VALUE
F2003 attribute, I'd expect the argument to be passed by value. Note
that even with BIND(C), arguments are passed in the normal Fortran way
(by reference, typically) unless you say VALUE. Therefore I do not
agree that stdref and stdcall should give you the same behavior with a
BIND(C) routine.

What I have in mind is (from n3661.pdf, section 15.2.6):

"(5) any dummy argument without the VALUE attribute corresponds to a
formal parameter of the prototype that is of a pointer type, and
the dummy argument is interoperable with an entity of the
referenced type (C standard, 6.2.5, 7.17, and 7.18.1) of the
formal parameter"

This seems to me to say that with BIND(C), the mode of argument
passing is not the normal Fortran way, but constrained to be
interoperable with a C pointer formal parameter if VALUE is not
specified. Thus the BIND(C) should, in my view, override the
default to pass by value which could be set by /iface:stdcall.

I'll tell you that I am somewhat uncomfortable with the idea of mixing
BIND(C) and /iface switches to produce some sort of combined
characteristic. My preferred style is to never use /iface and if I
need something different in an interface I use the appropriate syntax
(whether it be BIND(C) or !DEC$ ATTRIBUTES ) to get it. I have a
personal dislike of switches that change the meaning of code. I
understand their expedient use in porting situations, but I'd try to
dissuade you from using them in new code.

I feel your pain here. I can imagine the support issues you get from
users who have to set separate switches for every source file. I am
hoping to find a syntax for invoking Win32 API functions that has a
chance to work across multiple compilers. When, in about 10 years
(isn't that about the time it takes, e.g. it took about 15 years from
introduction of the 80386 to acceptance of xp, and x86-64 was introduced
roughly 5 years ago) everyone is running 64-bit Windows, the /iface:
switches shouldn't be necessary; they're just a temporary expedient
needed to cope with the zoo that is 32-bit Windows.

There's also a quirk of our compiler you are apparently not aware of.
Compiling a module (containing interfaces) with a specific /iface
option does nothing useful. That option is applied only when the
interface is used - it is not recorded as a property of the module. It
is for this reason we added the DEFAULT attribute back in the CVF days
- this tells the "user" of the interface to ignore all command line
options that change calling and naming conventions - so that you could
say everything you wanted to in an interface and not have it change
when the user compiled with, say, /names:lowercase. Personally, I
would have not chosen to design it this way, but that's the way it was
done some 15 years ago and we have to live with it.

Excellent. This is one of the reasons for my paragraph requoted above:
there were several design choices that your compiler team could have
made here, and I wanted to flesh out what your design philosophy was.
As an optimist, I assumed that gfortran and g95 might be able to make
different choices. In that way, by constraining an interface block to
be interpreted in the context of the compiler evironment in effect at
the time of its compilation, gfortran could specify different calling
conventions for different procedures invoked by the same program without
introducing any new features, just possibly fixing bugs in the current
feature set. This is something that may be more likely for an advocate
to persuade the implementors to realize than new extensions.

If that meant that every Win32 API interface block had to have a
!DEC$ attributes STDCALL, DECORATE line in addition to the BIND(C)
stuff (so that other vendors either followed my proposal or the
Directive Enhanced Compilation way), that wouldn't be so bad. Even if
every vendor needed their own line of stuff in every interface block
it wouldn't be so bad. What starts to get dicey is if all the code
that uses it need preprocessor editing all over the place to work
across different compiler systems or if you need to write wrappers
in fasm or something for all the function calls.

Yeah, that seems inconsistent with the BIND(C) characteristics, like
the fact that only character variables with length 1 are allowed.
The requirement to pass this value of 1 every time seems not to
permit the degree of control a C program has over its interface.

I agree this is odd, but the idea seems to be that you are passing an
array of characters, not a character variable in the Fortran sense.

Again from n3661.pdf:

"(3) the number of dummy arguments of the interface is equal to the
number of formal parameters of the prototype"

I read that as precluding the possibility of passing the length
implicitly.

What I do is declare

character(kind=C_CHAR) lpString

in the C function interface and then declare

character(kind=C_CHAR) message*(80)

in the Fortran caller then pass message like a normal argument.
Is this the normal way even though you are telling the compiler
that the callee only wants a single character by reference? If
the caller passed an expression, would the compiler be justified
in only computing the first character of the expression and
passing a reference to that?

I would not think so. It's perfectly acceptable to pass a longer
string to a routine which declares the argument to be shorter (though
not the other way around).

Reading n3661.pdf a little more carefully, I am starting to feel
more confident that the way I am doing things is correct and safe.

Thank you very much for the valuable feedback!

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


.



Relevant Pages

  • Re: Win32 API and gfortran
    ... write out a module containing only interface blocks and compile the ... that the /iface switches and ATTRIBUTES directives change the compiler ... arguments are passed in the normal Fortran way ... There's also a quirk of our compiler you are apparently not aware of. ...
    (comp.lang.fortran)
  • Re: changing module files
    ... my previous post (Will Fortran 2003 Solve This Problem). ... C++ header files avoid that problem, because header files only declare the ... INTERFACE to class member functions. ... > Just because the implemention of the compiler is not in a standard does ...
    (comp.lang.fortran)
  • Re: How calling a cpp-dll?
    ... | In cpp the string is correct, but the string in Fortran is empty. ... You should tell the compiler that StdVar_String uses whatever calling ...
    (comp.lang.fortran)
  • Re: NAG ware linking problem
    ... Adding the following interface block ought to do the trick. ... subroutine antfarm() bind ... If you don't have version 5.1 of the compiler, ... Basically, all Fortran procedure ...
    (comp.lang.fortran)
  • Re: Speed Test between C and Fortran 95
    ... Besides selecting the best compiler optimization switches, ... you turn off development-level switches, such as bounds checking, ... interface checking, etc. ...
    (comp.lang.fortran)