I can make module variables protected so that they cannot be changed in Fortran outside the module, but if I share them with C, they can be changed in the C code. Is there a workaround? For example, compiling and running
module constants_mod
use iso_c_binding, only: c_double
implicit none
real(kind=c_double), bind(c), protected :: pi, sqrt_2
contains
subroutine set_constants()
pi = 3.14159265359_c_double
sqrt_2 = 1.41421356237_c_double
end subroutine set_constants
end module constants_mod
program main
use constants_mod, only: set_constants
interface
subroutine print_constants() bind(c)
end subroutine print_constants
end interface
call set_constants()
call print_constants()
call print_constants()
end program main
with
#include <stdio.h>
double pi, sqrt_2;
void print_constants() {
printf("\npi = %f",pi);
printf("\nsqrt_2 = %f",sqrt_2);
pi = pi*2; // bad
}
gives
pi = 3.141593
sqrt_2 = 1.414214
pi = 6.283185
sqrt_2 = 1.414214
I think that the problem that you have to contend with is your expectation that a restriction that you specify in the Fortran program (protected) should be known to and honored/enforced by the C routine, or vice versa.
Do the C-interoperability rules in the applicable Fortran standard specify such behavior?
If not, that level of cooperation between the Fortran compiler and its companion C compiler may exist with certain compiler pairs, but not so with others. If you do not trust the C compiler and/or the C routine to leave your shared variables unchanged, only make “throwaway” copies available to C; load the copies with values before calling C; make the call, and reload the copies after the C call returns.
The parameter atribute conflicts with the bind(c) attribute. That alone suggests interoperability of constants is problematic - presumably because C’s global constants are basically macros. I would either interop copies of the original constants (as @mecej4 recommended), or just define print_constants with arguments, something like:
program main
use constants_mod!, only: set_constants
implicit none
interface
subroutine print_constants(pi, sqrt_2) bind(c)
use iso_c_binding, only: c_double
real(kind=c_double), value :: pi, sqrt_2
end subroutine print_constants
end interface
call set_constants()
call print_constants(pi, sqrt_2)
call print_constants(pi, sqrt_2)
end program main
with
#include <stdio.h>
void print_constants(const double pi, const double sqrt_2) {
printf("\npi = %f",pi);
printf("\nsqrt_2 = %f",sqrt_2);
pi = pi*2; // This will cause an error, as it should!
}
If print_constants really needs to modify the constants, it should define local copies of those. However, I realize this is just a stripped short example of the real code. If said real code needs to modify pi or sqrt_2, remove the const attribute in C-side. Even then, the original constants in F-side will remain intact.
I’m a bit late to the party, but the extern keyword is necessary on the C side.
const double pi;
This defines an uninitialized const variable pi. (Sadly, it is valid C to leave it uninitialized!)
extern const double pi;
This declares that somewhere, in a different object file, there will be a const variable pi, and the linker should go and find it. Since the actual definition is in your fortran module, this is the form that you want for the C code.
The const keyword basically means “read-only”. It’s less formal than fortran’s parameter keyword.