- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
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
Link Copied
6 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page