Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29256 Discussions

Fortran -e03 not giving warning for C_LOC and character strings

breitenfeld
Beginner
949 Views
I have a question as to why, when I compile (using 10.1) the following code with ifort -e03, the compiler does not give a warning:

PROGRAM main
USE ISO_C_BINDING
CHARACTER(LEN=2, KIND=C_CHAR), TARGET :: chr
TYPE(C_PTR) :: chr_ptr
chr_ptr = C_LOC(chr)
END PROGRAM main

For the C_LOC(X) function X must be interpretable and for a character the standard says:

15.2.1 Interoperability of intrinsic types
3 Table 15.2 shows the interoperability between Fortran intrinsic types and C types. A Fortran intrinsic
4 type with particular type parameter values is interoperable with a C type if the type and kind type
5 parameter value are listed in the table on the same row as that C type; if the type is character, inter
6 operability also requires that the length type parameter be omitted or be specified by an initialization
7 expression whose value is one.

so doesn't the standard require

CHARACTER(LEN=1, KIND=C_CHAR), TARGET :: chr(2)
or
CHARACTER(KIND=C_CHAR), TARGET :: chr(2)

Thanks



0 Kudos
6 Replies
Steven_L_Intel1
Employee
949 Views
I'm inclined to agree with you. There's an interesting side-issue that a CHARACTER(2) actual argument is allowed to match a CHARACTER(1,KIND=C_CHAR), DIMENSION(2) dummy argument (12.4.1.2). I'll let the developers know about this.
0 Kudos
breitenfeld
Beginner
949 Views
Exactly, this code is standard compliant:

MODULE modtest
USE ISO_C_BINDING
CONTAINS
SUBROUTINE One( chr )
CHARACTER(LEN=1, KIND=C_CHAR), DIMENSION(*), TARGET :: chr
TYPE(C_PTR) :: chr_ptr
chr_ptr = C_LOC(chr)
END SUBROUTINE One
END MODULE modtest

PROGRAM main
USE ISO_C_BINDING
USE modtest
CHARACTER(LEN=8, KIND=C_CHAR), DIMENSION(1:4) :: chr
chr(1) = '00000001'
chr(2) = '00000002'
chr(3) = '00000003'
chr(4) = '00000004'
CALL One( chr )
END PROGRAM main

BUT, say you add a generic interface and have a multi-dimension array of character strings of size>1, then we see the problem with passing a character string with length X into a dummy character argument array LEN=1 but of size X, for example:

MODULE modtest
USE ISO_C_BINDING
INTERFACE One
MODULE PROCEDURE Two
END INTERFACE
CONTAINS
SUBROUTINE Two( chr )
CHARACTER(LEN=1, KIND=C_CHAR), DIMENSION(*), TARGET :: chr
TYPE(C_PTR) :: chr_ptr
chr_ptr = C_LOC(chr)
END SUBROUTINE Two
END MODULE modtest

PROGRAM main
USE ISO_C_BINDING
USE modtest

CHARACTER(LEN=8, KIND=C_CHAR), DIMENSION(1:4) :: chr
CHARACTER(LEN=2, KIND=C_CHAR), DIMENSION(1:4, 1:4) :: chr2

chr(1) = '00000001'
chr(2) = '00000002'
chr(3) = '00000003'
chr(4) = '00000004'

chr2(1,:) = '01'
chr2(2,:) = '02'
chr2(3,:) = '03'
chr2(4,:) = '04'

CALL One( chr2 )

END PROGRAM main

Now the compiler will not see an interface for One(chr2), but if you were to just

CALL Two(chr2)

instead it will work fine.

For higher order arrays you would have to add another routine for each dimension of the array you added up to 7 times if needed, not very elegant:

SUBROUTINE Three( chr, ndim1 )
CHARACTER(LEN=1, KIND=C_CHAR), DIMENSION(ndim1,*), TARGET :: chr
TYPE(C_PTR) :: chr_ptr
chr_ptr = C_LOC(chr)
END SUBROUTINE Three

Thankfully some compilers have extended the standard to LEN>1.


0 Kudos
Steven_L_Intel1
Employee
949 Views
I believe that the compiler is not required to give a standards diagnostic in this case, as the rule being violated is neither a numbered syntax rule nor a constraint. It is the requirement on the programmer to comply with the stated rule. Given the way intrinsic modules are defined in the standard, it may not be feasible to diagnose such violations.
0 Kudos
Steven_L_Intel1
Employee
949 Views
The developers agree with my last statement. Diagnosis of this is not required by the standard, and since C_LOC is a module procedure and not an intrinsic procedure, we don't even have a good way of detecting this misuse. It is incumbent on the programmer to follow the rule - we're not going to try to check for it.
0 Kudos
breitenfeld
Beginner
949 Views
I'm assuming that your last 2 comments are in regards to my second reply in this thread.

The following code to me looks to be standard compliant, as you mentioned the CHARACTER(LEN=4) actual argument is allowed to match a CHARACTER(LEN=1,KIND=C_CHAR), DIMENSION(4) dummy argument (12.4.1.2). But the compiler will not recognize subroutine 'Two' as a valid interface for the call indicated. So if you are going by the standard you can not use a generic interface to handle a scalar character (len>1) and an array of characters (keeping in mind that all the subroutines have to have LEN=1 so that you can use C_LOC). That is why I really appreciate intel (among others) extending the standard such that C_LOC(X) can accept character X with LEN>1.

MODULE modtest

USE ISO_C_BINDING

INTERFACE One
MODULE PROCEDURE Two
END INTERFACE

CONTAINS
SUBROUTINE Two( chr )
CHARACTER(LEN=1, KIND=C_CHAR), DIMENSION(1:4) :: chr
PRINT*,chr(1:4)
END SUBROUTINE Two
END MODULE modtest


PROGRAM main
USE ISO_C_BINDING
USE modtest

CHARACTER(LEN=4, KIND=C_CHAR) :: chrScalar
chrScalar = 'Scal'

! This does not work

CALL One( chrScalar )

! This works

CALL Two( chrScalar )

END PROGRAM main


0 Kudos
Steven_L_Intel1
Employee
949 Views
My last two comments were regarding your initial issue about C_LOC. I would not say that we "extended the standard", but rather don't have a good way of enforcing the standard's requirement of an interoperable type.

Unfortunately, generic resolution does not seem to have been extended to allow for what you want. It strictly requires "TKR" (Type, Kind and Rank) match. You might need a jacket routine that in turn calls the C routine with the C_CHAR interface.
0 Kudos
Reply