ISO_C_BINDING: questions about VALUE and INTENT(IN)

Back to basics, I am trying to figure out some things about C interoperability using @milancurcic 's book, the latest “Modern Fortran explained” and the Fortran 2018 standard. But I stumble on these questions related to VALUE and INTENT() statements:

  1. Consider a Fortran interface to a C function with a declaration such as:
	integer(c_int), value, intent(in) :: i

If the argument is passed by value, the C function will work on a copy: so does the intent(in) statement have any interest or effect? Or is is just informative?

And the Fortran 2018 Interpretation Document says in section 8.5.18:

C864 An entity with the VALUE attribute shall not have the ALLOCATABLE, INTENT (INOUT), INTENT(OUT), POINTER, or VOLATILE attributes.

If intent(out) and intent(inout) are forbidden, intent(in) seems implicit, isn’t it?

  1. If we pass an argument by reference:
	type(my_type), intent(in) :: my_struct

how can the Fortran compiler verify that the C function does not modify it? If the dummy argument in the C function is declared with the const statement, maybe the linker could check the consistency with the Fortran declaration, looking in the C header file? But if the const statement if absent, who knows what happens in the C function? Is there any mechanism to check, at compilation time, that the intent(in) is respected?

1 Like

Wrt your first question, I wouldsay that INTENT(IN) is superfluous but it does not contradict the VALUE attribute. Perhaps that is why it is allowed, to stress the characteristics.

Wrt your second question: the Fortran compiler cannot check that, specifically as the argument is passed by reference. It might pass a temporary copy instead of the thing itself, but I am not familiar enough with the inner workings of compilers. (Note: you can lie to the compiler about the actual characteristics if the body of the subprogram is outside a module and that is the case with C functions)

As for const: does that cause a change in the linking behaviour?

1 Like

For whatever it’s worth, here’s how I look at it:

  1. A Fortran processor can also serve as a companion C processor effectively enabling the functioning of bind(C,..) procedures in what is otherwise all Fortran code, meaning the semantics and associated constraints of interoperability with C processor are positively employed in such programs to achieve certain goals. Under the circumstances, the INTENT(IN) provides all the benefits associated that Fortran attribute in those subprograms.
  2. But with code with external subprograms using processors other than Fortran, yes one can argue the INTENT(IN) is mostly informational but a valuable one at that nonetheless.

Please see my comments above. With Fortran code with bind(C,..) the INTENT attribute provides the safety with effective read-only access to the dummy argument. But with external subprograms with processors other than Fortran, you’re right in that there is no real guardrail against the violation of the stated INTENT!

Thanks @FortranFan for your precise answer.

If I understand your point 1., you are talking about a Fortran code where some interfaces have the bind(c,...) attribute, but not for binding to a C function. I never thought about that. Probably you said too much or not enough about that :slight_smile: I am interested to know more about that technique.

yes one can argue the INTENT(IN) is mostly informational but a valuable one at that nonetheless.

Concerning that point, my opinion is that it can also be misleading if the reader is not conscious that the compiler can not check that.

WRT point 1, value has impact for things other than just bind(c). If one does not specify intent(in), then the dummy argument can be modified within the body of the procedure, but if it has the value attribute then it does not affect the actual argument. C functions behave the same way if const is not specified.

WRT to point 2, and related to point 1, there is nothing that states the compiler (“processor”) must check that the Fortran interface and C prototype match. It is entirely the programmers responsibility to ensure that they match. This is one of the biggest dangers of mixed language programming and thus something that one must be very careful about and test thoroughly.

On a related note, I have a video on getting started with mixed Fortran and C programming: Just Talk to Each Other: Getting Fortran and C to Work Together - YouTube

I apologize for reviving this old post (old but very useful), but I’d like to highlight that utilizing intent(in) has the advantage of enabling the bind procedure to be declared as pure , expanding its potential usage, such as in conjunction with do concurrent .

1 Like

But it may not be pure on the C side, for example there could be a printf() in the C code and the Fortran compiler would not check the C code.

Whereas a print * in a pure subroutine on the Fortran side would be refused:

Error: PRINT statement at (1) not allowed within PURE procedure
1 Like

I don’t recommend this except in rare circumstances where you understand the consequences (or are just doing it temporarily for debugging purposes), but I have in fact used this aspect to “cheat” the compiler and be able to get around the restrictions in pure procedures.