C bindings for a global variable

Is it possible to use C bindings for a global variable that is defined as a parameter? I was attempting something like the following.

module test
    use iso_c_binding
    implicit none
    integer(c_int), bind(C, name="c_globalparam"), parameter :: globalparam = 123
end module

This results in a compilation error in ifort

test.f90(4): error #6406: Conflicting attributes or multiple declaration of name.   [GLOBALPARAM]

(An error is similarly produced using gfortran.) In both cases this works without the parameter attribute. Is it possible to use C bindings for a global parameter as in my example? Thanks.

2 Likes

It helps to think of anything PARAMETER as not a runtime object, it’s a named constant, not a variable. Only variables can be interoperable. The following is an explanatory note from the Standard:

The following are examples of the usage of the BIND attribute for variables and for a common
block. The Fortran variables, C_EXTERN and C2, interoperate with the C variables, c_extern
and myVariable, respectively. The Fortran common blocks, COM and SINGLE, interoperate
with the C variables, com and single, respectively.

MODULE LINK_TO_C_VARS
   USE, INTRINSIC :: ISO_C_BINDING
   INTEGER(C_INT), BIND(C) :: C_EXTERN
   INTEGER(C_LONG) :: C2
   BIND(C, NAME=’myVariable’) :: C2
   COMMON /COM/ R, S
   REAL(C_FLOAT) :: R, S, T
   BIND(C) :: /COM/, /SINGLE/
   COMMON /SINGLE/ T
 END MODULE LINK_TO_C_VARS
 /* Global variables. */
 int c_extern;
 long myVariable;
 struct { float r, s; } com;
 float single;

This restriction does not seem necessary. A type object declared in C with the qualifier const can also be used as a named constant.
So perhaps both objects (in Fortran and C) can be interoperable:

integer, parameter, bind(c) :: i
const int i

Given the differences in semantics with the const qualifier in C relative to the named constant in Fortran, chances are high the Fortran standard will always have the restriction. In principle, one can change the value of a const qualified object in C through a pointer reference. These are but aspects that make C a low-level systems programming language. Restrictions in interoperability with C are likely rather good for the kind of practitioners who would want to use Fortran.

#include <stdio.h>
int main(void)
{
   const int i = 1;
   printf("i (initially) = %d\n", i);
   int* pi = &i; (*pi)++;
   printf("i (following pointer increment) = %d\n", i);
   return 0;
}

C:\Temp>c.exe
i (initially) = 1
i (following pointer increment) = 2

Interestingly, I got mixed results with the above code using both gcc (v. 11.2.1) and icc (v. 2021.5.0) in linux:

rudi@landau|temp>gcc const_obj_incremented.c              
const_obj_incremented.c: In function ‘main’:
const_obj_incremented.c:6:14: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qua
lifiers]
6 |    int* pi = &i; (*pi)++;
|              ^
rudi@landau|temp>./a.out
i (initially) = 1
i (following pointer increment) = 2
rudi@landau|temp>icc const_obj_incremented.c 
const_obj_incremented.c(6): warning #2331: a value of type "const int *" cannot be used to initialize an entity of type "int *" (dropping qualifiers)
     int* pi = &i; (*pi)++;
               ^
rudi@landau|temp>./a.out 
i (initially) = 1
i (following pointer increment) = 1

It’s curious that both compilers complain about the initialization of the pointer, instead of the increment.
Also, notice that with gcc the variable is incremented, whereas with icc it’s not.
I don’t know about the status of these compilers with the current standard C17.

It seems that the above-noted different behavior of the C compilers is permitted by the C17 standard.
Looking at the draft (N2310.pdf), section 6.7.3:

If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.

So neither compiler violates the standard. That would indeed affect the interoperability of these objects.

How about

program main
  integer, parameter :: param=30
  call sub(param)
  print *,param
end program main
subroutine sub(i)
  integer:: i
  i = 20
end subroutine sub

It may segfault (and actually does on my Linux gfortran 11) but I doubt Standard can guarantee that a PARAMETER object is stored in write-protected RAM.
Actually in ancient times FORTRAN (then all upper case) was (in)famous for accidentally changing all instances of the same literal constant just by the mechanism shown above.

The Standard guarantees that it is possible for the compiler to eliminate named constants entirely from the program.

2 Likes

But the only way I can think of is to replace them with literal constants which IMHO does not clear the problem