[MPI3 Fortran] Fwd: [Mpi-comments] MPI 3.0: Fortran 2008 interface - issue with the LOGICAL kind

Tobias Burnus burnus at net-b.de
Thu Feb 28 16:10:58 CST 2013


N.M. Maclaren wrote:
> Drop ALL of the BIND(C) from the functions, as they aren't currently 
> conforming. Plain INTEGER is not guaranteed to be
> interoperable, and nor is DOUBLE PRECISION (Wtime, Wtick). I hope to 
> make default types more interoperable in the next standard, but
> that hasn't even been discussed yet.

That's probably the simplest. The actual implementation might even use C 
binding in this case, iff the Fortran interface is already interopable 
with C, e.g. integer matches "int" etc. For logicals, it could either 
make sure to only use the .true./.false. values for the Fortran compiler 
or to ensure other values are properly handled. [0 and 1 seems work 
correctly with all compilers I tested and might be a reasonable 
assumption for an implementation (but not the MPI spec itself).] Whether 
there is a bind(C) or not should undetectable from the user program. If 
the Fortran interface is not interoperable, the MPI implementation can 
then still use a wrapper.


N.M. Maclaren wrote:
> On Feb 28 2013, Craig Rasmussen wrote:
>>> The real question is what (integer) value does .TRUE._C_BOOL have?

Currently? My experience is that you get with most compilers 1 but with 
some compilers -1.

>> Would great damage be done to the international standard gods if 
>> .TRUE._C_BOOL evaluates to the integer value 1? I guess the C 
>> programmer has to know what value (not processor dependent) to set it to.

Well, the C99 standard states: "When any scalar value is converted to 
_Bool, the result is 0 if the value compares equal to 0;
otherwise, the result is 1." ("6.3.1.2 Boolean type").

> I can't see why it should be. It's not the solution I proposed, but is 
> in many ways simpler.

I also do no see a problem with requiring that .TRUE._C_BOOL evaluates 
to 1. One could argue that the current standard (F2008 combined with 
C99) already mandates this for interoperability. (A clarification in the 
Fortran standard wouldn't harm, however.)

(But I do not see how that would help. The problem with the current MPI 
specification is not that logical(C_BOOL) doesn't interoperate with 
_Bool but that it currently uses "LOGICAL", which is on most systems not 
the same as _Bool.)


Bill Long wrote:
> The fatal flaw in the MPI interface here is that the corresponding C 
> formal parameter is not _Bool or anything that looks like LOGICAL. 
> Instead it is 'int'.

I mostly concur, except that the Fortran and the C code do not need to 
have the same data type. (Well, unless one insists that the binding name 
is the same, which the current MPI spec implies via "bind(C)".) If one 
doesn't require the same binding name, one could use logical(C_bool) or 
something else on the Fortran side – while C uses "int".


Craig Rasmussen wrote:
> 1. Suppose a compiler has a default logical size equivalent to a 
> default integer. Since the standard only requires one logical kind, 
> this compiler may not have a type that is interoperable with a _Bool C 
> type. In this instance C_BOOL would be a negative value.

As written, 32bit Darwin seems to use sizeof(_Bool) == 4 by default. 
And, thus, sizeof(int)==sizeof(_Bool). However, that doesn't imply that 
a compiler cannot support _Bool. It just means that _Bool only should 
have the values 0 and 1 while "int" can have any value. That's not 
different to the more common sizeof(_Bool) == 1, which is not the same 
as "signed char" even if both have the same size. In any case, the byte 
size is independent from whether the Fortran+accompanying C compiler 
supports _Bool or not (i.e. c_bool < 0).

> 3. Suppose a Fortran compiler has the following mapping:
> _Bool flag = 0; /* flag maps to .FALSE. */
> if (flag != 0) ...; /* flag maps to .TRUE. */
> This seems to me to be the sane way to map values from C to Fortran. 
> The same mapping can be done for any C integer type to an equivalently 
> sized Fortran LOGICAL.

First, in C99, "flag != 0" is not a _Bool but an "int" (see C99, "6.5.9 
Equality operators"). Secondly, is it completely unclear what you mean 
by "a Fortran compiler has". "flag != 0" is not a valid Fortran 
expression and whether the compiler translates a "logical(c_bool)" 
variable into assembler code which resembles "flag != 0" or not is 
really compiler dependent. A simple "if(flag)" on an x86 system will 
likely be translated into "jz" or "jnz" (jump if zero or jump if not 
zero); that will regard any nonzero integer as .true. However, ".not." 
can be implemented by flipping a single bit, if true is always "1" (or, 
e.g., "-1"). If the compiler expects 0 and 1 and flips the respective 
bit, then ".not." of "-1" will give "-2" which in conditions (via 
jz/jnz) is regarded as .true. as is -1. That issue occurs with GCC for 
Fortran's logicals (and also for C99's _Bool); seemingly, NAG's Fortran 
compiler does something similar in some cases.


N.M. Maclaren wrote:
> On Feb 28 2013, Craig Rasmussen wrote:
>>> (3) Or one forces the compiler to accept also other values than 
>>> .true./.false. As with the previous item, it will affect also all 
>>> non-Bind(C) logicals. And C_Bool should presumably excluded as one 
>>> otherwise might get in trouble with the C compiler.
>>
>> It seems it has to anyway to be compatible with C. I don't have the 
>> C99 standard but it appears that there isn't a constant for "true" 
>> and "false" without including stdbool.h. Thus a Fortran compiler will 
>> have to anticipate values other than .true./.false.
>
> true and false are specified to be 1 and zero in stdbool.h.

I think most C programmers regard them as canonical values for true and 
false - and use them as such. (It is also in line with C99's _Bool). 
Also from the Fortran side I would be fine with using those. (I am not 
sure whether all vendors would be.) However, it is nearly certain that 
most C programmer will assume that "int" <-> logical(c_int) will work 
such that any nonzero integer is regarded as .true., even if we write in 
the Fortran standard that only 1 and 0 are supported. That will lead to 
difficult to find wrong-code problems, which depend on the compiler, the 
optimization flag and the expression.


>>> (4) Last, handling dummy arguments/result variables of BIND(C) 
>>> procedures differently. That probably would work, but it requires a 
>>> bunch of the careful addition of additional constraints. For 
>>> instance, to prohibit the TARGET/POINTER attribute for those.
>>
>> To me this is the only sane response given that C evaluates 0 to 
>> false and everything else to true. Nick you want to weigh in on the C 
>> standard.
>
> Tempting, but no. I will say that I can see no reason to prohibit the 
> TARGET/POINTER attribute according to whether BIND(C) is there.

Do you mean in terms of the consistency/conciseness of the standard? Or 
in terms of a reason why it would be needed?

I assume the former. But regarding the latter: Assume "-1" is passed to 
a "LOGICAL(kind=4), target :: dummy". Then "logical(kind=4), pointer :: 
ptr; ptr => dummy" will cause problems: Either "ptr" is "-1" but the 
compiler does not know that the value has to be treated in a special 
way. Or the compiler changes "ptr" to "1" on entering the BIND(C) 
procedure – which gives a segfault if "-2" is in read-only memory. Or it 
creates a copy, which doesn't work as soon as the value is changed 
through "ptr" and read via "dummy" (or vice versa). Thus, prohibiting 
TARGET/POINTER seems to be required to allow for a different internal 
representation.

I can perfectly understand that one doesn't want to go this route, but 
if one does, such a constraint seems to be required.

Tobias



More information about the mpiwg-fortran mailing list