Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29241 Discussions

Why does ISO_C_BINDING require VALUE attrribute on dummy argument?

newfortranuser
Beginner
1,794 Views

Hi again.

Consdier the following Fortran routine:

integer function demo( k ) bind(C)
use, intrinsic :: ISO_C_BINDING, only: C_INT
implicit none
integer(C_INT), intent(in), value :: k

integer :: i

i = k ! fatal runtime if value attribute is removed above

demo = 0

return

end function demo

If I invoke that routine from C using either

int foo = demo(100)

or

int argument = 100

int foo = demo(argument)

everything runs as expected. But why should I need the VALUE attribute on the dummy variable k? Surely the ISO_C_BINDING is supposed to take care of the calling conventions! If I remove the VALUE attribute, the code still compiles and links. But I get a fatal runtime error (undefined address) on the i = k assignment. Notice that I am not trying to make an assignment *to* the dummy argument. I'm just trying to *use* the value which I expect to have passed via the dummy argument. This has all the hallmarks of trying to use reference semantics on a value object. But again, should not the ISO_C_BINDING take care of this? I'm pretty sure I've seen examples of floating-point code which work wthout the VALUE attribute.

So far I have tried this only for C_INT. I figure I should not even try C_FLOAT or C_CHAR until I understand how C_INT works. I have also been reading ISO/IEC FCD 1539-1:2004(E) but have not found an explanation for the behavior I see. If anyone can explan this, I'd appreciate it. Useful pointers into the standard are also welcome.

I am using IVF 11.1.054

Thanks.

0 Kudos
1 Solution
Steven_L_Intel1
Employee
1,794 Views

First of all, ISO_C_BINDING has nothing to do with this. It's just a module with declarations. What you're really asking is if BIND(C) changes the argument passing convention to be "by value". The answer to that is "No". The standard sez....

4 A Fortran procedure interface is interoperable with a C function prototype if
5 (1) the interface has the BIND attribute;
6 (2) either
7 (a) the interface describes a function whose result variable is a scalar that is interoperable
8 with the result of the prototype or
9 (b) the interface describes a subroutine, and the prototype has a result type of void;
10 (3) the number of dummy arguments of the interface is equal to the number of formal parameters
11 of the prototype;
12 (4) any dummy argument with the VALUE attribute is interoperable with the corresponding
13 formal parameter of the prototype;
14 (5) any dummy argument without the VALUE attribute corresponds to a formal parameter
15 of the prototype that is of a pointer type, and the dummy argument is interoperable with
16 an entity of the referenced type (C International Standard, 6.2.5, 7.17, and 7.18.1) of the
17 formal parameter; and
18 (6) the prototype does not have variable arguments as denoted by the ellipsis (...).

View solution in original post

0 Kudos
7 Replies
newfortranuser
Beginner
1,794 Views

I forgot to mention that in my C++ code I have declared demo() external as follows:

extern "C" int demo(int kappa);

And my OP is just a stripped down example. I am actually able to pass (integer) values back and forth both on the stack and on the heap to do useful work, provided that the stack values are declared with the VALUE attribute.

I'm hoping I've done something trivially foolish. Otherwise, I can share an example project with premier support.

0 Kudos
newfortranuser
Beginner
1,794 Views

Changing the definition of the function to

integer(C_INT) function demo( k ) bind(C)

did not help but is probably a good idea.

0 Kudos
Steven_L_Intel1
Employee
1,795 Views

First of all, ISO_C_BINDING has nothing to do with this. It's just a module with declarations. What you're really asking is if BIND(C) changes the argument passing convention to be "by value". The answer to that is "No". The standard sez....

4 A Fortran procedure interface is interoperable with a C function prototype if
5 (1) the interface has the BIND attribute;
6 (2) either
7 (a) the interface describes a function whose result variable is a scalar that is interoperable
8 with the result of the prototype or
9 (b) the interface describes a subroutine, and the prototype has a result type of void;
10 (3) the number of dummy arguments of the interface is equal to the number of formal parameters
11 of the prototype;
12 (4) any dummy argument with the VALUE attribute is interoperable with the corresponding
13 formal parameter of the prototype;
14 (5) any dummy argument without the VALUE attribute corresponds to a formal parameter
15 of the prototype that is of a pointer type, and the dummy argument is interoperable with
16 an entity of the referenced type (C International Standard, 6.2.5, 7.17, and 7.18.1) of the
17 formal parameter; and
18 (6) the prototype does not have variable arguments as denoted by the ellipsis (...).

0 Kudos
newfortranuser
Beginner
1,794 Views

Thank you, Steve. What you've been telling me finally dropped into place.

What I take from this is

(1) The ISO_C_BINDING module is just declarations/definitions.

(2) The ISO_C_BINDING module is just declarations/definitions. Really!

(3) The interoperability of Fortran 2003 does little more than require implementors to observe the order of formal arguments/parameters, the return value and the long-ago established value/reference semantics for each of these.

I was blinded by a preconceived and misplaced hope that Fortran 2003 was going to free me from ever having to think about calling conventions again. I was so wrong. So blinded, I managed to miss the very direct language in the standard. Thank you for setting me straight. Clear now. I'm even passing character data back and forth now and appreciate the C_NULL_CHAR very much.

Thanks for patiently explaining this.

0 Kudos
Steven_L_Intel1
Employee
1,794 Views

Well, actually, Fortran 2003 does free you. When you are coding in C you need to keep straight whether an argument is expected as int or *int. Same in Fortran.

The C interoperability features free you from vendor extensions to specify things such as pass-by-value, knowing how derived types are padded, knowing how various types are returned as function results, and having a portable way of declaring Fortran variables that match up with corresponding variables in C. Oh, naming conventions are also eased.

What confuses a lot of people, including at one point some of our own developers, is that BIND(C) is not the same as our !DEC$ ATTRIBUTES C.

The C interop features are very powerful and, for the first time, allow writing portable, standard-conforming code that calls and can be called by C. This is nothing to sneeze at. There's really a lot going on behind the scenes, especially in cases where Fortran compilers create their own conventions. (For example, how is a COMPLEX function value returned? Fortran and C do it differently by default.) No hidden arguments allowed when using BIND(C)!

0 Kudos
newfortranuser
Beginner
1,794 Views

I see your point. As an occasional Fortran user over several generations of the DEC compiler I was just as happy with !DEC$ since it was (is) consistent over time. Yes, learning it the first time was confusing. But I got pretty good at using it. I do see that the new way ensures portability, which !DEC$ does not. And I for one say "good riddance!" to hidden length arguments!

Thanks!

0 Kudos
Steven_L_Intel1
Employee
1,794 Views
Do understand that not being able to have hidden arguments means that some Fortran concepts are not usable in C interoperability. For example, character where length is greater than 1, functions returning arrays, etc.
0 Kudos
Reply