Given that you canāt enforce it for C procedures, Iād be hesitant to require this for Fortran.
In C++ you have namespaces, e.g.
namespace fpm {
// ...
}
In C things can go wrong in very subtle ways due to macros, function-like macros and inline
functions. Say you offer an API with the following interface:
// process_api.h
void process(int N, double x[N]);
Now someone else might inadvertently use N
, a capitalized identifier as a constant, e.g.
// definitions.h
#define N 42
Next, they write a main program:
#include "definitions.h"
#include "process_api.h" // boom!
int main(void) {
double x[4] = {1.,2.,3.,4.};
process(4,x);
return 0;
}
This will fail to compile as the substitution of N
will invalidate the header. You can fix it by swapping the order the headers are imported in. But some day you might import a third header, or hit the via a transitive header.
You can also suffer clashes with the standard library; if you would pick I
as a dummy variable in a header, all it takes to break the code is to #include <complex.h>
which provides I
as a macro for the imaginary unit. Not to mention the potential clashes with the name process
itself.
What can you do to avoid the problem? In general you prefix all public and internal functions. For the dummy arguments in the public header you can either omit the variables names, use comments or prefixed identifiers:
void pp_process(int, double []); // omit
void pp_process(int /*n*/, double[] /*x*/); // inline comments
void pp_process(int pi_n, double pi_x[pi_n]); // prefixed (pp - public, pi - internal)
You can also face clashes with member names in struct
and union
types. Hereās a mixed C/C++ example:
// main.cpp
#include "ISO_Fortran_binding.h"
template<int rank>
class FortranArray {
private:
CFI_CDESC_T(rank) desc;
};
int main(int argc, char const *argv[])
{
FortranArray<5> array;
/* code */
return 0;
}
The code look okays, but in fact there is a name clash between the template parameter, and a member of the unnamed C descriptor struct hidden underneath the CFI_CDESC_T
macro.
$ g++ main.cpp
In file included from main.cpp:1:
main.cpp:6:2: error: declaration of āCFI_rank_t FortranArray<rank>::<unnamed struct>::rankā shadows template parameter
6 | CFI_CDESC_T(rank) desc;
| ^~~~~~~~~~~
main.cpp:3:10: note: template parameter ārankā declared here
3 | template<int rank>
| ^~~
For C++, namespaces should take care of most of the problems. But for a C header, to be on the safe side you need to prefix all identifiers: types (both struct
or not), struct
and union
members, variables, enumerations, macros, functions, and function-like macros. You can take the "ISO_Fortran_binding.h"
header as an example; everything is prefixed with CFI_
.
For C, I imagine this could be difficult to enforce. Perhaps some large C projects have developed tools to maintain name hygiene. (cc @vmagnin, maybe you are familiar with how GTK handles this?)