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.
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:
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.
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.