Am I missing something here? f2003A.f90 works with
some compilers, f2003B.f90 works with others:
#!/bin/sh
################################################################################
cat > getkey.c <<\EOF
/* C function that returns C type char */
char getkeyC(void) {
char c;
c='A';
return(c);
}
EOF
################################################################################
cat > f2003A.f90 <<\EOF
! make Fortran/C interface for C routine getkeyC(3C)
! this works with g95, ifort, ...
module M_getkey
use iso_c_binding
implicit none
public
interface
function getkeyC() bind(c, name='getkeyC')
use iso_c_binding
implicit none
integer(kind=c_char) :: getkeyC
end function getkeyC
end interface
contains
function getkey()
character(kind=c_char) :: getkey
getkey=char(getkeyC())
end function getkey
end module M_getkey
program test_getkey
use M_getkey
character :: A
A=getkey()
write(*,*)'LETTER ',A
end program test_getkey
EOF
################################################################################
cat > f2003B.f90 <<\EOF
! make Fortran/C interface for C routine getkeyC(3C)
! this works with gfortran, ...
module M_getkey
use iso_c_binding
implicit none
public
interface
function getkey() bind(c, name='getkeyC')
use iso_c_binding
implicit none
character(kind=c_char) :: getkey
end function getkey
end interface
end module M_getkey
program test_getkey
use M_getkey
character :: A
A=getkey()
write(*,*)'LETTER ',A
end program test_getkey
EOF
################################################################################
# G95
cc -c getkey.c
g95 f2003A.f90 getkey.o -o getkeyC
#########################################
# GFORTRAN
cc -c getkey.c
gfortran f2003B.f90 getkey.o -o getkeyI
#########################################
# INTEL
icc -c getkey.c
ifort f2003A.f90 getkey.o -o getkeyI
################################################################################
> integer(kind=c_char) :: getkeyC
(snip)
> ################################################################
> character(kind=c_char) :: getkey
This is an interesting problem. Since char in C is really
a small integer type, it isn't so obvious that it should
not be an INTEGER kind in Fortran, but Fortran 2003 specifically
indicates that C_CHAR is a CHARACTER type.
Since KIND is just a small integer, it would seem that
compilers might not diagnose it if the value indicated a
valid KIND for the appropriate type.
What does F2003B.f90 do on the compilers it doesn't work on?
-- glen
C_CHAR returns a character kind number corresponding to the C "char"
type. Thus, it should only be used to declare CHARACTER variables, and
your second example (the one compiling with gfortran) is the right thing
to do. The fact that other compilers do not compile it is a bug in the
compilers.
However, I see that gfortran throws an error when trying to compile the
first program. While, as I said, you should *not* write such a program, I
believe it's still valid, because you're lucky and the value of C_CHAR is
1, which happens to be a perfectly valid integer kind number. So, unless
I have missed a constraint in the standard, I think your first program
may be standard-conforming if you have the luck of C_CHAR matching a
valid integer kind (probably true for the most common compilers). Thus,
while gfortran is helping you avoid this nonportable code, I think a hard
error is overdoing it and a warning would be sufficient.
Now of course, in C a "char" is just an integer type. So, if you really
want to get that value as an integer in Fortran, you should use an
integer of the kind C_SIGNED_CHAR, which is designed for that purpose.
Hope this helps!
--
FX
It seems to be popular for the KIND to correspond to the number
of bytes in the data type, except for COMPLEX.
INTEGER(KIND=C_CHAR) might give a one byte INTEGER (on machines
with one byte (char).
> However, I see that gfortran throws an error when trying to compile the
> first program. While, as I said, you should *not* write such a program, I
> believe it's still valid, because you're lucky and the value of C_CHAR is
> 1, which happens to be a perfectly valid integer kind number. So, unless
> I have missed a constraint in the standard, I think your first program
> may be standard-conforming if you have the luck of C_CHAR matching a
> valid integer kind (probably true for the most common compilers). Thus,
> while gfortran is helping you avoid this nonportable code, I think a hard
> error is overdoing it and a warning would be sufficient.
There is the requirement that the appropriate KIND exist, but
it would seem that way to me.
> Now of course, in C a "char" is just an integer type. So, if you really
> want to get that value as an integer in Fortran, you should use an
> integer of the kind C_SIGNED_CHAR, which is designed for that purpose.
Interesting that the INTEGER kind C_SIGNED_CHAR works for both
(signed char) and (unsigned char).
A common implementation of C functions is to return the result
in a processor register, usually the same size as an (int)
for (int), (short), or (char) result type.
-- glen
> However, I see that gfortran throws an error when trying to compile the
> first program. While, as I said, you should *not* write such a program, I
> believe it's still valid, because you're lucky and the value of C_CHAR is
> 1, which happens to be a perfectly valid integer kind number. So, unless
> I have missed a constraint in the standard, I think your first program
> may be standard-conforming if you have the luck of C_CHAR matching a
> valid integer kind (probably true for the most common compilers). Thus,
> while gfortran is helping you avoid this nonportable code, I think a hard
> error is overdoing it and a warning would be sufficient.
I'd agree, with the additional comment that it is actually
non-conforming for gfortran to refuse to compile the code, as it is
perfectly valid code as long as there does happen to be such an integer
kind (which is almost always true). It is non-portable, it is a really
bad idea to intentionally code that way, and it has high odds of being a
mistake. But it is technically valid.
That's an excellent example of the kind of thing warnings are for.
--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
> function getkeyC() bind(c, name='getkeyC')
> use iso_c_binding
> implicit none
> integer(kind=c_char) :: getkeyC
Using INTEGER(kind=c_char) is not allowed according to the standard, you
need to use integer(kind=c_signed_char) if you need an integer - or as
you did below CHARACTER(kind=c_char) is also OK.
(Using C_CHAR for an INTEGER is possible, if it happens that the kind
number is the same as C_SIGNED_CHAR, but that cannot necessarily
assumed. In case of gfortran, that is the case, but the person writing
the BIND(C) part seemingly wanted to have a strict implementation and
thus C_CHAR is rejected.)
With INTEGER you al also might run into trouble if your signed character
becomes negative ...
To quote the Fortran 2003 standard, in "15.1.1 Named constants and
derived types in the module" one finds:
"The value of C_CHAR shall be a valid value for a character kind type
parameter on the processor or shall be -1. The value of C_CHAR is known
as the C character kind."
Thus C_CHAR is reserved for the CHARACTER type. For INTEGER one finds:
"The value of C_INT shall be a valid value for an integer kind parameter
on the processor. The values of C_SHORT, C_LONG, C_LONG_LONG,
C_SIGNED_CHAR, C_SIZE_T, C_INT8_T, C_INT16_T, C_INT32_T, C_INT64_T,
C_INT_LEAST8_T, C_INT_LEAST16_T, C_INT_LEAST32_T, C_INT_LEAST64_T,
C_INT_FAST8_T, C_INT_FAST16_T, C_INT_FAST32_T, C_INT_FAST64_T,
C_INTMAX_T, and C_INTPTR_T shall each be a valid value for an integer
kind type parameter on the processor or shall be -1 if the companion C
processor defines the corresponding C type and there is no
interoperating Fortran processor kind or -2 if the C processor does not
define the corresponding C type."
> function getkey() bind(c, name='getkeyC')
> use iso_c_binding
> implicit none
> character(kind=c_char) :: getkey
> end function getkey
> end interface
If this doesn't work, it is a bug in the compiler. It works here with my
g95 (and with gfortran), but it also fails with my ifort.
Tobias
> Using INTEGER(kind=c_char) is not allowed according to the standard, you
> need to use integer(kind=c_signed_char) if you need an integer - or as
> you did below CHARACTER(kind=c_char) is also OK.
As noted elsethread, this is not entirely accurate. It is allowed; it
just doesn't mean what one might think and isn't what is wanted here (or
pretty much anywhere).
> To quote the Fortran 2003 standard, in "15.1.1 Named constants and
> derived types in the module" one finds:
>
> "The value of C_CHAR shall be a valid value for a character kind type
> parameter on the processor or shall be -1. The value of C_CHAR is known
> as the C character kind."
>
> Thus C_CHAR is reserved for the CHARACTER type.
The "thus" does not follow. It is not "reserved" in any sense. It is a
named constant (I'll use that term instead of the synonymous "parameter"
here to avoid confusion) and can be used in all the kinds of places
where such named constants can be used. It isn't restricted to being
used as a kind parameter at all.
Now "sensible" uses of it involve character kind parameters. The OP's
code should certainly not be doing what it does. But I think it
important to avoid implying that the standard treats this as some kind
of special thing that has its own special rules. That's not so. It is an
ordinary named constant.
If you want to do
write (*,*) 42.0**C_CHAR
then that's perfectly valid. I'm not sure why anyone would want to do
that, but it is valid Fortran.
My personal preference would have been for kind parameters to be of
derived types rather than integers, in which case there usage would
indeed be more restricted. But I'm afraid it is about 2 decades too late
for that one.
Tobias Burnus <bur...@net-b.de> wrote:
> (Using C_CHAR for an INTEGER is possible, if it happens that the kind
> number is the same as C_SIGNED_CHAR, but that cannot necessarily
> assumed. In case of gfortran, that is the case, but the person writing
> the BIND(C) part seemingly wanted to have a strict implementation and
> thus C_CHAR is rejected.)
Alas, such an implementation is not a "strict" implementation in the
sense of conforming to the standard. In being a bit strict with the
users on this, the compiler isn't being so strict in its own standard
conformance.
Compilers don't get to reject code just because they think the code is
ill advised or possibly not what the user intended. That's what warnings
are for, though.
I little clarification -- here's the history. ifort(1) and g95(1)
compiled BOTH f2003A.f90 and f2003B.f90; but I only got the expected
answer
LETTER A
when running f2003A.f90 with them; while gfortran(1) would only
compile f2003B.f90; but it also ran it the way I expected.
When method "B" failed on 2 out of 3 compilers, gfortran(1) looked
outvoted and I lost confidence in what I was doing; and
came up with method "A" and found gfortran(1) would not compile it. If
it had, I think I would have decided I had interpreted
things wrong and that the "integer" method was correct; but something
seemed wrong so I just went to passing simple integers
and using ICHAR(3F) to convert back to a letter a while ago; but this
had been bothering me ever since.
I was at a point where I wanted to report the problem, but wasn't sure
who had one! I truly appreciate the responses -- they
answered my questions and raised ones I hadn't even thought of. I
hadn't thought thru whether the compiler could or should
treat C_CHAR as a "reserved" kind or not, for example.
Since the code will ultimately run on compilers and platforms I don't
yet have new enough compilers on or current access to I
have been using the three that support ISO_C_BINDING that I have to
"answer questions". These responses have proven far more
informative!
So I think the consensus is:
f2003B.f90 should work. I should report this to Intel and upgrade my
g95(1) compiler. At a minimum f2003A.f90 should produce a
warning (gfortran(1) doing so was the best indication I had I was
going down the wrong path) but the typing of KIND in Fortran 2003
isn't strong enough to expect C_CHAR to act as a reserved, strictly
enforceable KIND so it should not be a hard compiler error?
If anyone can verify other compilers I'd appreciate it. For reference,
here are the full results from the ifort(1) and g95(1)
runs I made. I should note the g95(1) version I used was a beta
release, by the way ..
+ ifort -V
Intel(R) Fortran Intel(R) 64 Compiler Professional for applications
running on Intel(R) 64, Version 11.0 Build 20090131 Package ID:
l_cprof_p_11.0.081
Copyright (C) 1985-2009 Intel Corporation. All rights reserved.
+ icc -V
Intel(R) C Intel(R) 64 Compiler Professional for applications running
on Intel(R) 64, Version 11.0 Build 20090131 Package ID:
l_cproc_p_11.0.081
Copyright (C) 1985-2009 Intel Corporation. All rights reserved.
+ rm -f getkey.o testme
+ icc -c getkey.c
+ ifort getkey.o f2003B.f90 -o testme
+ ./testme
LETTER H
+ ./testme
+ cat -v -e -t
LETTER M-%$
+ g95 --version
G95 (GCC 4.0.3 (g95 0.91!) Feb 27 2008)
Copyright (C) 2002-2005 Free Software Foundation, Inc.
G95 comes with NO WARRANTY, to the extent permitted by law.
You may redistribute copies of G95
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING
+ gcc --version
gcc (GCC) 4.1.2 20070115 (SUSE Linux)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There
is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
+ rm -f getkey.o testme2
+ gcc -c getkey.c
+ g95 getkey.o f2003B.f90 -o testme2
+ ./testme2
LETTER
Script started on Fri May 8 19:46:03 2009
[?1034hsh-3.2$
sh-3.2$ g95 --version
G95 (GCC 4.0.3 (g95 0.92!) May 7 2009)
Copyright (C) 2002-2008 Free Software Foundation, Inc.
G95 comes with NO WARRANTY, to the extent permitted by law.
You may redistribute copies of G95
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING
sh-3.2$ g95 getkey.o f2003A.f90 -o testit
sh-3.2$ ./testit
LETTER A
sh-3.2$ g95 getkeyl .o f2003B.f90 -o testit
sh-3.2$ ./testit
LETTER A
sh-3.2$ exit
exit
Script done on Fri May 8 19:46:57 2009