Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

substrings and array sections

101 views
Skip to first unread message

Arjen Markus

unread,
Aug 17, 2012, 4:04:23 AM8/17/12
to
Hello,

I was reading the book "FORTRAN tools for VAX/VMS and MSDOS" by Jones and
Crabtree, and I suddenly realised the following:

Substring expressions like string(1:) or string(10:20) are very much alike
(syntactically) to array sections (array(1:) and array(10:20)), but unlike
array sections we can not select the characters using a stride:
string(1:10:3) to get every third character or string(10:1,-1) to reverse
a string.

There are probably very good reasons for this restriction. Or is it something
that never came up? Just curious - the use of such a feature is quite probably
very limited anyway and easily be mimicked with a function.

Regards,

Arjen

Paul Anton Letnes

unread,
Aug 17, 2012, 4:09:35 AM8/17/12
to
What about using a character array instead of a string? That should let
you slice as usual.

Paul

Arjen Markus

unread,
Aug 17, 2012, 5:04:16 AM8/17/12
to
Op vrijdag 17 augustus 2012 10:09:35 UTC+2 schreef Paul Anton Letnes het volgende:
Sure, that would be a solution, but when I saw in one of the source listings
how a string was reversed and I thought "well, we can do that in F2003 without
a do-loop ...", I realised that we can not do that without a do-loop.

Like I said, nothing major, just something that puzzled me - an asymmetry
as it were.

Regards,

Arjen

Paul Anton Letnes

unread,
Aug 17, 2012, 5:57:53 AM8/17/12
to
There are several asymmetries. Consider the following program:
program foo
implicit none

character(10) :: a
a = '1234567890'
print *, a(3)

end program foo

It fails when compiling with gfortran:
print *, a(3)
1
Error: Syntax error in PRINT statement at (1)

...because a single index isn't allowed. Asymmetric indeed!

Paul

Arjen Markus

unread,
Aug 17, 2012, 6:12:57 AM8/17/12
to
Op vrijdag 17 augustus 2012 11:57:53 UTC+2 schreef Paul Anton Letnes het volgende:
Oops, you are right - I did not realise that one :).

Regards,

Arjen

Robin Vowels

unread,
Aug 17, 2012, 8:57:55 PM8/17/12
to
On Aug 17, 6:09 pm, Paul Anton Letnes
<paul.anton.let...@nospam.gmail.kthxbai.com> wrote:
> On 17.08.12 10:04, Arjen Markus wrote:

> > I was reading the book "FORTRAN tools for VAX/VMS and MSDOS" by Jones and
> > Crabtree, and I suddenly realised the following:
>
> > Substring expressions like string(1:) or string(10:20) are very much alike
> > (syntactically) to array sections (array(1:) and array(10:20)), but unlike
> > array sections we can not select the characters using a stride:
> > string(1:10:3) to get every third character or string(10:1,-1) to reverse
> > a string.
>
> > There are probably very good reasons for this restriction. Or is it something
> > that never came up? Just curious - the use of such a feature is quite probably
> > very limited anyway and easily be mimicked with a function.

> What about using a character array instead of a string?

In PL/I, you can treat an array of characters as a single string.
declare s(10) character (1);
put (string(s));
As well as that, a string can be overlayed on an array of characters.

In Fortran, you can do:

INTEGER :: I
CHARACTER(LEN=10) :: S
CHARACTER(LEN=1) :: A(10)
EQUIVALENCE (S, A)

S = '1234567890'
PRINT *, A
DO I = 1, 10
PRINT *, A(I)
END DO
END

Paul Anton Letnes

unread,
Aug 18, 2012, 5:01:37 AM8/18/12
to
Aha. Is there a way of using this 'equivalence' trick to get strings
whose length are determined at runtime? Perhaps allocating the character
array, then equivalenc-ing the two? That's something I've been missing
sorely.

Paul


dpb

unread,
Aug 18, 2012, 8:36:13 AM8/18/12
to
On 8/18/2012 4:01 AM, Paul Anton Letnes wrote:
...

> ... Perhaps allocating the character array, then equivalenc-ing the two?...

NO! EQUIVALENCE is static storage alignment.

--

Robin Vowels

unread,
Aug 18, 2012, 9:02:52 AM8/18/12
to
On Aug 18, 7:01 pm, Paul Anton Letnes
Unfortunately no. EQUIVALENCE is for static storage only.

If you want something dynamic, TRANSFER might help.

PL/I, however, does provide run-time overlaying,
and is therefore available on non-varying strings and
character arrays whose length is determined at run time.

dpb

unread,
Aug 18, 2012, 9:20:01 AM8/18/12
to
Dang <RET> key in wrong place... :(

...

Excerpt from CVF doc on EQUIVALENCE outlines restrictions...unless it's
been somehow removed (and I'd doubt it strongly) in later Standard the
specific of an ALLOCATABLE is prohibited entirely since that isn't known
at compile-time when EQUIVALENCE storage association is resolved (that's
not Standard-speak but it's a decent description of what is entailed).

> The following objects cannot be specified in EQUIVALENCE statements:
>
> A dummy argument
> An allocatable array
> A pointer
> An object of nonsequence derived type
> An object of sequence derived type containing a pointer in the structure
> A function, entry, or result name
> A named constant
> A structure component
> A subobject of any of the above objects
...
> The same storage unit cannot occur more than once in a storage
> sequence, and consecutive storage units cannot be specified in a way
> that would make them nonconsecutive.

The last reemphasizes it works on the requirement of storage association
which again rules out the dynamic allocation.

You can, of course, use the old work-storage everything is a 1D vector
of large size and manually allocate subsets of it for various purposes
as was done for years prior to any of these newfangled things like
ALLOCATABLEs. I don't recommend it as a practice for retaining hair
when debugging, etc. :)

--

Gordon Sande

unread,
Aug 18, 2012, 9:23:15 AM8/18/12
to
Depends on what you have in mind for "determined at runtime". The usual
examples are
the Pascal method of a count of used characters in a character string
of some maximum
length or the C method of a sentinel (the null) to mark the end of the
used characters
in a character array of some maximum length. Both have variable length
but neither uses
dynamic storage allocation. The closest Fortran equivalent is the use
of TRIM to yield
a variable length portion of a character string where TRIM leaves off
all the trailing
blanks. If you want to do exactly what any one of these three methods
does then the other
two are a big bother. But each can be used readily on their own terms.
TRIM also comes
in the LEN_TRIM variation. The common problems of left or right
adjustment are functions
like TRIM. The whole collection of string maniputations is quite
complete and easy to
use as long as you accept them as a whole solution and not a bad
approximation to what
is in a C programming book. Sometimes this is described as Fortran
treating strings as
first class objects. The other language which does this is BASIC!





Dick Hendrickson

unread,
Aug 18, 2012, 11:29:21 AM8/18/12
to
One thing you can do to view character variables as either arrays or
strings is to pass them on to subroutines or functions. It's OK to pass
a character array to a procedure and declare it as a scalar character
variable of whatever length is appropriate. Ditto, scalars can be
turned into arrays across a call. (And arrays can be reshaped, etc.)
The only restriction is the obvious one that you can't make the variable
bigger on the called side. It's a little bit of a pain in the tush if
you're doing lots of manipulations in one expression. But if you need
to do a bunch of stuff in scalar string mode and then a bunch of stuff
in array mode, it's not so bad.

Dick Hendrickson

James Van Buskirk

unread,
Aug 18, 2012, 12:55:26 PM8/18/12
to
"Paul Anton Letnes" <paul.ant...@nospam.gmail.kthxbai.com> wrote in
message news:k0nllk$7rv$1...@dont-email.me...
C:\gfortran\clf\long_string>type string2.f90
program string2
use ISO_C_BINDING
implicit none
integer i
character(len=:,kind=C_CHAR), allocatable, target :: S
character(len=1,kind=C_CHAR), pointer :: A(:)
type(C_PTR) p

S = '1234567890'
p = C_LOC(S(1:1))
call C_F_POINTER(p,A,[len(S)])
write(*,'(11a)') 'A = ', A
do i = 1, size(A)
write(*,'(a,i0,2a)') 'A(',i,') = ',A(i)
end do
end program string2

C:\gfortran\clf\long_string>gfortran string2.f90 -ostring2

C:\gfortran\clf\long_string>string2
A = 1234567890
A(1) = 1
A(2) = 2
A(3) = 3
A(4) = 4
A(5) = 5
A(6) = 6
A(7) = 7
A(8) = 8
A(9) = 9
A(10) = 0

--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


Richard Maine

unread,
Aug 18, 2012, 1:57:23 PM8/18/12
to
Paul Anton Letnes <paul.ant...@nospam.gmail.kthxbai.com> wrote:

> There are several asymmetries. Consider the following program:
> program foo
> implicit none
>
> character(10) :: a
> a = '1234567890'
> print *, a(3)
>
> end program foo
>
> It fails when compiling with gfortran:
> print *, a(3)
> 1
> Error: Syntax error in PRINT statement at (1)
>
> ...because a single index isn't allowed. Asymmetric indeed!

To get a hint of why allowing that would be a problem, change the
declaration to, for example

character(10) :: a(4)

Then it runs fine with gfortran and produces the "expected" result (if
you expect the same thing I do).

After figuring out what it is doing, think about syntactic ambiguities.

There are also quite a few other things different about strings and
arrays. Some of them would not be easy to rectify because, as
illustrated above, you can have arrays of strings, making for
ambiguities. And don't forget about things like trincation or padding on
assignment, which is valid for strings, but not arrays.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain

James Van Buskirk

unread,
Aug 18, 2012, 2:52:34 PM8/18/12
to
"Dick Hendrickson" <dick.hen...@att.net> wrote in message
news:a99qmg...@mid.individual.net...

> One thing you can do to view character variables as either arrays or
> strings is to pass them on to subroutines or functions. It's OK to pass a
> character array to a procedure and declare it as a scalar character
> variable of whatever length is appropriate.

This is close to the truth, but not quite in my (and gfortran's) reading
of the standard. N1830.pdf, section 12.5.2.4:

"If a scalar dummy argument is default character or of type character
with the C character kind, the length len of the dummy argument shall
be less than or equal to the length of the actual argument. The dummy
argument becomes associated with the leftmost len characters of the
actual argument. If an array dummy argument is default character or of
type character with the C character kind and is not assumed shape, it
becomes associated with the leftmost characters of the actual argument
element sequence (12.5.2.11)."

So to associate an array of size 10 and len 1 with a scalar dummy of
len 10 you would have to make an intermediate call to an array dummy
of size 1 and len 10 and then pass the first element of this array
dummy as an actual argument so that the second procedure now can be
a scalar of the desired length. Of course, it may be that it is
sufficient to work with an array of size 1 and len 10.

> Ditto, scalars can be turned
> into arrays across a call. (And arrays can be reshaped, etc.)

Now, this is OK.

> The only restriction is the obvious one that you can't make the variable
> bigger on the called side. It's a little bit of a pain in the tush if
> you're doing lots of manipulations in one expression. But if you need to
> do a bunch of stuff in scalar string mode and then a bunch of stuff in
> array mode, it's not so bad.

An example with pointers:

C:\gfortran\clf\long_string>type string3.f90
module sideways
implicit none
private
public a2s, s2a
contains
function a2s(A,N)
integer N
character(N), target :: A(1)
character(N), pointer :: a2s

a2s => A(1)
end function a2s

function s2a(S,N)
integer N
character, target :: S(N)
character, pointer :: s2a(:)

s2a => S
end function s2a
end module sideways

program string3
use sideways
implicit none
character(:), pointer :: S1
character, allocatable, target :: A1(:)
character(:), allocatable, target :: S2
character, pointer :: A2(:)
integer i

A1 = transfer('1234567890',A1)
S1 => a2s(A1,size(A1))
write(*,'(2a)') 'S1 = ', S1
do i = 1, len(S1)
write(*,'(2(a,i0),2a)') 'S1(',i,':',i,') = ', S1(i:i)
end do
S2 = '1234567890'
A2 => s2a(S2,len(S2))
write(*,'(11a)') 'A2 = ', A2
do i = 1, size(A2)
write(*,'(a,i0,2a)') 'A2(',i,') = ', A2(i)
end do
end program string3

C:\gfortran\clf\long_string>gfortran string3.f90 -std=f2008 -ostring3

C:\gfortran\clf\long_string>string3
S1 = 1234567890
S1(1:1) = 1
S1(2:2) = 2
S1(3:3) = 3
S1(4:4) = 4
S1(5:5) = 5
S1(6:6) = 6
S1(7:7) = 7
S1(8:8) = 8
S1(9:9) = 9
S1(10:10) = 0
A2 = 1234567890
A2(1) = 1
A2(2) = 2
A2(3) = 3
A2(4) = 4
A2(5) = 5
A2(6) = 6
A2(7) = 7
A2(8) = 8
A2(9) = 9
A2(10) = 0

Paul Anton Letnes

unread,
Aug 20, 2012, 2:33:10 AM8/20/12
to
Interesting. What am I doing wrong then?

/private/tmp/paulanto % cat foo.f90
program foo
implicit none
character :: a(10)
a(1) = 'a'
a(2) = 'b'
a(3) = 'c'
a(4) = 'd'
a(5) = 'e'
a(6) = 'f'
a(7) = 'g'
a(8) = 'h'
a(9) = 'i'
a(10) = 'j'
call bar(a)

contains
subroutine bar(str)
implicit none
character(len=*) :: str

print *, str
end subroutine bar
end program foo
/private/tmp/paulanto % gfortran -Wall foo.f90
foo.f90:14.13:

call bar(a)
1
Error: Rank mismatch in argument 'str' at (1) (scalar and rank-1)

Arjen Markus

unread,
Aug 20, 2012, 4:20:06 AM8/20/12
to
Op maandag 20 augustus 2012 08:33:10 UTC+2 schreef Paul Anton Letnes het volgende:
Well, the argument you pass (a) is an array and the subroutine expects
a scalar. It is within the Fortran-C interface context that you can
interchange arrays and scalars.

Regards,

Arjen

dpb

unread,
Aug 20, 2012, 7:29:23 AM8/20/12
to
On 8/20/2012 1:33 AM, Paul Anton Letnes wrote:
> On 18.08.12 17:29, Dick Hendrickson wrote:
...

>> One thing you can do to view character variables as either arrays or
>> strings is to pass them on to subroutines or functions. It's OK to pass
>> a character array to a procedure and declare it as a scalar character
>> variable of whatever length is appropriate. Ditto, scalars can be
>> turned into arrays across a call. (And arrays can be reshaped, etc.)
>> The only restriction is the obvious one that you can't make the variable
>> bigger on the called side. It's a little bit of a pain in the tush if
>> you're doing lots of manipulations in one expression. But if you need
>> to do a bunch of stuff in scalar string mode and then a bunch of stuff
>> in array mode, it's not so bad.
>>
>> Dick Hendrickson
>
> Interesting. What am I doing wrong then?
>
> /private/tmp/paulanto % cat foo.f90
> program foo
> implicit none
> character :: a(10)
> a(1) = 'a'
> a(2) = 'b'
...
> a(8) = 'h'
> a(9) = 'i'
> a(10) = 'j'
> call bar(a)
>
> contains
> subroutine bar(str)
> implicit none
> character(len=*) :: str
>
> print *, str
> end subroutine bar
> end program foo
> /private/tmp/paulanto % gfortran -Wall foo.f90
> foo.f90:14.13:
>
> call bar(a)
> 1
> Error: Rank mismatch in argument 'str' at (1) (scalar and rank-1)

I'm not sure what Dick is driving at--unless he's talking of the
C-interop that Arjen seems to think but that surely doesn't come across
if so. I can't think how he'd do what it says, specifically.

The code above is more explicitly (leaving out all but the essential)

program foo
...
character(len=1) :: a(10)
...

subroutine bar(str)
character(len=1) :: str
..

where I've substituted the actual for the length parameter in the
subroutine. The mismatch is apparent there--actual argument is an
array, the dummy isn't: that's not legal.

You can get by most compilers if you don't use module features so the
program units are compiled separately (and if necessary, use separate
files to prevent cross-module inter-ops/diagnosis) but the length of str
in the subroutine will be character*1 not 10. Your program done that way...

program test
character*1 :: a(10)

a(1)='a'
a(2)='b'

call foo(a)
end


subroutine foo(str)
character*(*) :: str

write(*,*) str
write(*,*) 'Len=', len(str)
end subroutine

C:\Temp> df /nologo test.f90
test.f90

C:\Temp>

NB the result is just 'a'

--

James Van Buskirk

unread,
Aug 20, 2012, 8:43:05 AM8/20/12
to
"Arjen Markus" <arjen.m...@gmail.com> wrote in message
news:11cdfbb4-6934-488f...@googlegroups.com...

> Op maandag 20 augustus 2012 08:33:10 UTC+2 schreef Paul Anton Letnes het
> volgende:

No, the new rule is a consequence of C interop but it works through
sequence association so no bind(C) stuff is required for it to work.
However, sequence association seems only to be applicable for array
dummy arguments so you need another level of indirection to get to
a scalar dummy argument.

C:\gfortran\clf\long_string>type string4.f90
program foo
implicit none
character :: a(10)
a(1) = 'a'
a(2) = 'b'
a(3) = 'c'
a(4) = 'd'
a(5) = 'e'
a(6) = 'f'
a(7) = 'g'
a(8) = 'h'
a(9) = 'i'
a(10) = 'j'
call bar1(a)

contains
subroutine bar1(array)
character, contiguous :: array(:)
call bar2(array, size(array))
end subroutine bar1

subroutine bar2(array,n)
integer n
character(n) array(1)
call bar(array(1))
end subroutine bar2

subroutine bar(str)
implicit none
character(len=*) :: str

print *, str
end subroutine bar
end program foo

C:\gfortran\clf\long_string>gfortran string4.f90 -ostring4

C:\gfortran\clf\long_string>string4
abcdefghij

dpb

unread,
Aug 20, 2012, 9:21:25 AM8/20/12
to
On 8/20/2012 7:43 AM, James Van Buskirk wrote:
...

> However, sequence association seems only to be applicable for array
> dummy arguments so you need another level of indirection to get to
> a scalar dummy argument.
...

Ah, yes...

--

Paul Anton Letnes

unread,
Aug 20, 2012, 9:41:54 AM8/20/12
to
This is patently insane, but entertaining reading. Thanks, James.

I now realize that you can probably use an automatic
character(len(character_array)) with the same length as the character
array, and write a subroutine strcopy which copies the character(:)
array into the character(*); that's probably cleaner. The character
array could be allocatable, hence, you'd have a variable string, sort of.

Paul

Gordon Sande

unread,
Aug 20, 2012, 10:08:30 AM8/20/12
to
I think the original comment was a desire for string with "runtime
varaible length".
I tried to point out that most examples of such are of a variable
amount of usage of an otherwise fixed data structure. There are several
ways that this is achieved. By counts
in Pascal, by the null sentinel in C or by the trailing blanks in
Fortran removed with
TRIM. I am still unsure whether you have been lead to believe that you
need a dynamicly
allocated data structure when these old techniques have done what you
seem to have asked
for. The newfangled methods get lots of glory for doing what you asked
for but there are
also the golden oldy oldfangled techniques that do the job. New ain't
always the improvement
that the hype suggests. Maybe there is some aspect of your problem that
does require
the dynamic allocation but I have not seen it mentioned.

I believe that the use of a character array as a runtime format has
some special rules
that result in the elements being concatenated. I haven't looked it up
but that is
what I recall.





Dick Hendrickson

unread,
Aug 20, 2012, 10:41:59 AM8/20/12
to
Basically, I misremembered something and, since I "knew" what I
remembered, I didn't bother to try it or look it up; sigh. I was away
from my computer over the weekend and couldn't agree with James'
correction until now.

Dick Hendrickson

A. M.

unread,
Aug 20, 2012, 2:45:46 PM8/20/12
to
Consider this:

CHARACTER(LEN=10) :: S
CHARACTER(LEN=1) :: A(10)
:
:
CALL array_string(s,10)
:
:
CALL scalar_string(a,10)
:
:
where

SUBROUTINE array_string(a,n)
INTEGER, INTENT(IN) :: n
CHARACTER(LEN=1) :: a(n)
:
:
SUBROUTINE scalar_string(a,n)
INTEGER, INTENT(IN) :: n
CHARACTER(LEN=n) :: a

Only Gfortran 4.6.3 catches the second Call and protests for rank
missmatch. It accepts the first call though.

The following accept both calls:
Ifort version 12.0.0 20101116
G95 (GCC 4.1.2 (g95 0.93!) Jun 16 2010)
Sun Fortran 95 8.6 Linux_i386 2011/11/16
OpenUH/Open64 Compiler Suite: Version 4.2
Silverfrost FTN95 6.20.0 Mon Dec 19 00:34:27 2011 (in wine)




James Van Buskirk

unread,
Aug 20, 2012, 3:08:17 PM8/20/12
to
"A. M. " <mygd...@ath.forthnet.gr> wrote in message
news:1345488343.272320@athprx03...

> Consider this:

> CHARACTER(LEN=10) :: S
> CHARACTER(LEN=1) :: A(10)
> :
> :
> CALL array_string(s,10)
> :
> :
> CALL scalar_string(a,10)
> :
> :
> where

> SUBROUTINE array_string(a,n)
> INTEGER, INTENT(IN) :: n
> CHARACTER(LEN=1) :: a(n)
> :
> :
> SUBROUTINE scalar_string(a,n)
> INTEGER, INTENT(IN) :: n
> CHARACTER(LEN=n) :: a

> Only Gfortran 4.6.3 catches the second Call and protests for rank
> missmatch. It accepts the first call though.

> The following accept both calls:
> Ifort version 12.0.0 20101116
> G95 (GCC 4.1.2 (g95 0.93!) Jun 16 2010)
> Sun Fortran 95 8.6 Linux_i386 2011/11/16
> OpenUH/Open64 Compiler Suite: Version 4.2
> Silverfrost FTN95 6.20.0 Mon Dec 19 00:34:27 2011 (in wine)

There is not enough information in your post to be able to
determine whether the interface was made explicit in the caller and
whether standards checking was enabled for compilation.

Richard Maine

unread,
Aug 20, 2012, 4:07:40 PM8/20/12
to
A. M. <mygd...@ath.forthnet.gr> wrote:

> Consider this:
>
> CHARACTER(LEN=10) :: S
> CHARACTER(LEN=1) :: A(10)
> :
> :
> CALL array_string(s,10)
> :
> :
> CALL scalar_string(a,10)
> :
> :
> where
>
> SUBROUTINE array_string(a,n)
> INTEGER, INTENT(IN) :: n
> CHARACTER(LEN=1) :: a(n)
> :
> :
> SUBROUTINE scalar_string(a,n)
> INTEGER, INTENT(IN) :: n
> CHARACTER(LEN=n) :: a
>
> Only Gfortran 4.6.3 catches the second Call and protests for rank
> missmatch. It accepts the first call though.
>
> The following accept both calls:
> Ifort version 12.0.0 20101116
> G95 (GCC 4.1.2 (g95 0.93!) Jun 16 2010)
> Sun Fortran 95 8.6 Linux_i386 2011/11/16
> OpenUH/Open64 Compiler Suite: Version 4.2
> Silverfrost FTN95 6.20.0 Mon Dec 19 00:34:27 2011 (in wine)

Well, the first call is valid Fortran, as discussed in this thread, so
I'd hope that all the compilers accepted it.

As to the second call, as James mentions, there isn't enough information
to determine whether one ought to expect compilers to be able to
diagnose it. In general, you often don't get diagnostics for argument
mismatches unless there is an explicit interface. That's one of the many
reasons to make it a habit to use explicit interfaces (preferably by
putting procedures in modules). Sometimes some compilers will notice
such mismatches in special cases, such as if both the call and the
subroutine are in the same source file, but you can't count on it in
general.

John Harper

unread,
Aug 20, 2012, 6:09:47 PM8/20/12
to
The transfer intrinsic makes converting between dynamic character arrays and
strings easy, and reversing the order is easy for the array, e.g. this
program

program testtransfer
implicit none
character(8):: string = 'foobar '
character(1),allocatable:: charray(:)
allocate(charray(len_trim(string)))
charray = transfer(trim(string),charray)
print *,'"',charray(size(charray):1:-1),'"'
string = transfer(charray,string)
print *,'"',string,'"'
end program testtransfer

prints

"raboof"
"foobar"

BTW if the first print statement was changed to

print *,'"'//charray(size(charray):1:-1)//'"'

then it printed "r""a""b""o""o""f". I was at first surprised that // and
comma can have different effects when separating character items in a print
list but of course they do in one like that.

--
John Harper

Klaus Wacker

unread,
Aug 21, 2012, 4:11:12 AM8/21/12
to
John Harper <john....@vuw.ac.nz> wrote:
>
> The transfer intrinsic makes converting between dynamic character arrays and
> strings easy, and reversing the order is easy for the array, e.g. this
> program
>
> program testtransfer
> implicit none
> character(8):: string = 'foobar '
> character(1),allocatable:: charray(:)
> allocate(charray(len_trim(string)))
> charray = transfer(trim(string),charray)
> print *,'"',charray(size(charray):1:-1),'"'
> string = transfer(charray,string)
> print *,'"',string,'"'
> end program testtransfer
>
> prints
>
> "raboof"
> "foobar"
>

I am confused about the result of the second print statement and the
assignment before. string ist still a character(8) variable, but only
6 characters are printed. I would naively have expected blank
padding. I added a few more print statements:

program testtransfer
implicit none
character(8):: string = 'foobar '
character(1),allocatable:: charray(:)
print *,'"',string,'"'
print *,ichar(string(7:7)),ichar(string(8:8))
allocate(charray(len_trim(string)))
charray = transfer(trim(string),charray)
print *,'"',charray(size(charray):1:-1),'"'
string = transfer(charray,string)
print *,'"',string,'"'
print *,'"',string(7:8),'"'
print *,ichar(string(7:7)),ichar(string(8:8))
end program testtransfer

and got the result:

"foobar "
32 32
"raboof"
"foobar"
""
0 0

string(7:8) are set to zero - is that what is expected according to
the standard? Is it standard conforming to print zero characters? If
so, is the result (i.e. to render nothing, not even a blank) standard
conforming?



--
Klaus Wacker klaus.w...@t-online.de
51°29'7"N 7°25'7"E http://www.physik.tu-dortmund.de/~wacker

A. M.

unread,
Aug 21, 2012, 4:41:03 AM8/21/12
to
Richard Maine wrote:

>
> A. M. <mygd...@ath.forthnet.gr> wrote:
>
<snip>
>> Only Gfortran 4.6.3 catches the second Call and protests for rank
>> missmatch. It accepts the first call though.
>>
>> The following accept both calls:
>> Ifort version 12.0.0 20101116
>> G95 (GCC 4.1.2 (g95 0.93!) Jun 16 2010)
>> Sun Fortran 95 8.6 Linux_i386 2011/11/16
>> OpenUH/Open64 Compiler Suite: Version 4.2
>> Silverfrost FTN95 6.20.0 Mon Dec 19 00:34:27 2011 (in wine)
>
> Well, the first call is valid Fortran, as discussed in this thread,
so
> I'd hope that all the compilers accepted it.
>
> As to the second call, as James mentions, there isn't enough
information
> to determine whether one ought to expect compilers to be able to
> diagnose it. In general, you often don't get diagnostics for argument
> mismatches unless there is an explicit interface. That's one of the
many
> reasons to make it a habit to use explicit interfaces (preferably by
> putting procedures in modules). Sometimes some compilers will notice
> such mismatches in special cases, such as if both the call and the
> subroutine are in the same source file, but you can't count on it in
> general.
>

Well, Richard and James, you are right. I forgot to mention how the
test was performed. The subroutines were called with implicit interface
and yes, they were in the same file with the caller. With explicit
interface the test does not work.

But does the "success" of the test mean that "esoterically" the scalar
and the array string are treated the same way, probably both as C-
strings with the added length for the scalar one?



Klaus Wacker

unread,
Aug 21, 2012, 6:59:59 AM8/21/12
to
OK, the last question I can partially answer myself, after having
redirected the output to a file and opened it with emacs. It does
contain zeros. It is just the console that renders them as nothing,
emacs shows ^@. That is after all to be expected from A format
conversion - no conversion at all. And list-directed formatting with a
character variable should behave the same.

The question how string(7:8) come to be zero remains.

dpb

unread,
Aug 21, 2012, 9:38:41 AM8/21/12
to
On 8/21/2012 5:59 AM, Klaus Wacker wrote:
...
>> John Harper<john....@vuw.ac.nz> wrote:
...
...[elided first example since repeated re: ? below for brevity]...

>> I am confused about the result of the second print statement and the
>> assignment before. string ist still a character(8) variable, but only
>> 6 characters are printed. I would naively have expected blank
>> padding. I added a few more print statements:
...[which I elided to see the actual code more clearly and didn't put
back]...
>> program testtransfer
>> implicit none
>> character(8):: string = 'foobar '
>> character(1),allocatable:: charray(:)

>> allocate(charray(len_trim(string)))
>> charray = transfer(trim(string),charray)
>> string = transfer(charray,string)
>> end program testtransfer
>>
>> and got the result:
>>
...

>> 0 0
>>
>> string(7:8) are set to zero - is that what is expected according to
>> the standard? ...
>
> OK, the last question I can partially answer myself, after having
> redirected the output to a file and opened it with emacs. It does
> contain zeros. It is just the console that renders them as nothing,
> emacs shows ^@. That is after all to be expected from A format
> conversion - no conversion at all. And list-directed formatting with a
> character variable should behave the same.

You can't really presume list-directed formatting "should" behave in any
particular way aiui--it's pretty much the discretion of the implementor
to include blanks, etc., at their discretion...but that's merely a side
note...

> The question how string(7:8) come to be zero remains.

charray was allocated the size of LEN_TRIM(string) which is 6.

The Standard says when the size of the TRANSFER is smaller than the
physical representation of the target the remaining is undefined. So
'0' is as good an undefined value as any and likely arises from the
implementation just clearing the target in preparation of a store.

BTW, the CVF implementation results in the same output...

--

Richard Maine

unread,
Aug 21, 2012, 10:50:54 AM8/21/12
to
In addition to the standard-speak about the remaining part being
undefined, let me comment that it would be quite surprising for TRASNFER
to blank fill. The main point of TRANSFER is that it copies bits without
regard to type. It is a form of "type cheating". Blank filling is
something very specific to character type (and even then only to a few
very specific situations with character type). The concept of a blank
doesn't even make sense for types other than character. One should not
expect TRANSFER to do such type-specific things as blank fill.

I might add that I personally very rarely use TRANSFER, and I would not
use it for something like this. I think of it as being much more related
to low-level bit twiddling. It is pretty esoteric from a high-level
language perspective. For example, I don't see that the standard
actually guarantees it will have the effect observed in this case. The
standard's definition of TRANSFER just involves "physical
representation". I can't imagine any scheme of physical representation
that is reasonably plausible for actual compilers and would not work.
Various requirements on things that do have to work (notably sequence
association) mean that a compiler would have to do pretty obscure and
messy things to make anything other than the "obvious" physical
representations work. But I can't see that it is actually guaranteed by
the standard, particularly in contexts that do not directly involve
sequence association. Yes, sequence association almost invariably (as in
I know of no exceptions) relates to physical memory layout, but the
standard doesn't quite say that. I'm not prepared to argue the question
in detail. I'm just saying that it is messy enough that I can't be
confident of the answer. It is far too messy and subtle. An argument is
unlikely to be able to convince me that I understand every subtlety
involved. Convincing me that I personally understand every possible
subtlety is quite a lot higher barrier than just being correct,
particularly as I am not overly excited about spending hours studying
this particular question. I do think it most improbable that it would
fail on any actual compiler; my uncertainty is more theorectical than
practical.

glen herrmannsfeldt

unread,
Aug 21, 2012, 12:32:18 PM8/21/12
to
Klaus Wacker <klaus.w...@t-online.de> wrote:

(snip)
>>> allocate(charray(len_trim(string)))
>>> charray = transfer(trim(string),charray)

(snip)
>> I am confused about the result of the second print statement and the
>> assignment before. string ist still a character(8) variable, but only
>> 6 characters are printed. I would naively have expected blank
>> padding. I added a few more print statements:

Try it with bounds checking turned on.

(snip)
> The question how string(7:8) come to be zero remains.

Note that len_trim(string) is 6, so characters from an array
of length 6 are being transfered to an array of length 8.

-- glen


dpb

unread,
Aug 21, 2012, 1:44:17 PM8/21/12
to
On 8/21/2012 11:32 AM, glen herrmannsfeldt wrote:
...

> Note that len_trim(string) is 6, so characters from an array
> of length 6 are being transfered to an array of length 8.
...

But, it could just as correctly left the previous bits alone...which is
sorta' what one might expect excepting that the Standard says the
behavior of the non-targetted locations when target representation space
is larger than the source is undefined. So, you can't count on anything
specific other than '0' is pretty good bet owing to implementation
details as RM notes in his more detailed follow-up.

--

James Van Buskirk

unread,
Aug 21, 2012, 6:11:31 PM8/21/12
to
"A. M. " <mygd...@ath.forthnet.gr> wrote in message
news:1345538458.481970@athprx03...

> Well, Richard and James, you are right. I forgot to mention how the
> test was performed. The subroutines were called with implicit interface
> and yes, they were in the same file with the caller. With explicit
> interface the test does not work.

> But does the "success" of the test mean that "esoterically" the scalar
> and the array string are treated the same way, probably both as C-
> strings with the added length for the scalar one?

Given implicit interface, all compilers probably passed three
arguments:

1) The address of the first character of the string or the first
element of the array.

2) The address of a memory location containing the value
10 = Z'0000000A'.

3) The value of the length of the character argument, 10 for S and 1
for A; on 64-bit processors this value should be a 64-bit value
(INTEGER(C_SIZE_T)) but gfortran unfortunately doesn't follow this
pattern. On 32-bit processors the value should be 32-bits in size.

You could write a C function to intercept these arguments and check
them out for yourself, or for that matter a Fortran subroutine with
the BIND property that can examine the arguments the same way a C
function could.

James Van Buskirk

unread,
Aug 21, 2012, 6:49:04 PM8/21/12
to
"Paul Anton Letnes" <paul.ant...@nospam.gmail.kthxbai.com> wrote in
message news:k0ter4$uhv$1...@dont-email.me...

> This is patently insane, but entertaining reading. Thanks, James.

> I now realize that you can probably use an automatic
> character(len(character_array)) with the same length as the character
> array, and write a subroutine strcopy which copies the character(:) array
> into the character(*); that's probably cleaner. The character array could
> be allocatable, hence, you'd have a variable string, sort of.

You don't actually need all those levels of subroutine call:

C:\gfortran\clf\long_string>type string5.f90
program foo
implicit none
character :: a(10)
a(1) = 'a'
a(2) = 'b'
a(3) = 'c'
a(4) = 'd'
a(5) = 'e'
a(6) = 'f'
a(7) = 'g'
a(8) = 'h'
a(9) = 'i'
a(10) = 'j'
call bar1(a)
call bar2(a,size(a))

contains
subroutine bar1(array)
use ISO_C_BINDING
implicit none
character(kind=C_CHAR), contiguous, target :: array(:)
character(size(array)), pointer :: str
type(C_PTR) p

! Bug which may be fixed in most recent gfortran but
! the most recent available at http://www.equation.com
! is from July 29.
! p = C_LOC(array(1))
p = transfer(LOC(array(1)),p)
call C_F_POINTER(p,str)
print *, str
end subroutine bar1

subroutine bar2(array,n)
implicit none
integer, value :: n
character(n) array(1)

print *, array(1)
end subroutine bar2
end program foo

C:\gfortran\clf\long_string>gfortran string5.f90 -ostring5

C:\gfortran\clf\long_string>string5
abcdefghij
abcdefghij

The advantage of these kinds of techniques is that they avoid
making copies of the array which can be a big deal for big
arrays. If a copy gets made and you modify the copy, then you
have to do extra work to modify the original, whereas with
aliases as in the code above, the original will be modified
when you alter it through the alias.
0 new messages