How do I initialize a character variable in fortran 77? - fortran

Consider the variable
character*100 xx
I want to initialize it to some value, possibly some printable character or blanks. I tried
data xx /100*char(120)/
But that did not work.
Minimum working example:
cat car_array.F
character*10 xx
data xx /10*char(120)/
write(*,*)xx
end
ifort car_array.F
car_array.F(2): error #6169: This construct is not valid in this context. [CHAR]
data xx /10*char(120)/
--------------------^
compilation aborted for car_array.F (code 1)

making a bold assumption that you don't really need to be f77 standard compliant,
you should try:
character*10 :: xx=repeat(char(120),10)
in f77 you would have needed to make this a runtime assignment,
character*10 xx
integer i
do i=1,10
xx(i:i)=char(120)
end do
the only way i see to use a repeat count data statement to initialize a string in f77 is via equivalence with a length 1 character array, and here you can not use the char function
equivalence(x,y)
character*10 x
character*1 y(10)
data y/10*'a'/
write(*,*)x
aaaaaaaaaa

Very similar to agentp's post.
You can use the CHAR() function indirectly if you use it in a compile-time PARAMETER statement.
Old-timey, but this works on openVMS Fortran.
PARAMETER CHAR_120 = CHAR(120)
CHARACTER*1 X(10) /10*CHAR_120/
CHARACTER*10 XX
EQUIVALENCE (X, XX)
TYPE *,XX

Related

FORTRAN subroutine thinks the length of a string I'm passing it is not what it is

stackoverflow. First-time poster, long-time reader. I am working on debugging a large program (that started in F77 but has evolved), and I'm getting a runtime error that the string I'm passing a subroutine is shorter than expected. The thing is, I'm putting in a debug statement right before calling the subroutine, and the string is indeed of the correct length. Can you help me figure this one out? Since the code is long I'll just post the relevant snippet of file her1pro.F here (note WORD="HUCKEL " with a space at the end, but this happens to all the strings):
SUBROUTINE PR1INT(WORD,WORK,LWORK,IORDER,NPQUAD,
& TRIANG,PROPRI,IPRINT)
...
CHARACTER WORD*7
...
WRITE(*,*)"LB debug, calling PR1IN1 from PR1INT"
WRITE(*,*)"LB debug, WORD=",WORD
WRITE(*,*)"LB debug, LENGTH(WORD)=",LEN(WORD)
CALL PR1IN1(WORK,KFREE,LFREE,WORK(KINTRP),WORK(KINTAD),
& WORK(KLBINT),WORD,IORDER,NPQUAD,TRIANG,
& PROPRI,IPRINT,DUMMY,NCOMP,TOFILE,'TRIANG',
& DOINT,WORK(KEXPVL),EXP1EL,DUMMY)
...
SUBROUTINE PR1IN1(WORK,KFREE,LFREE,INTREP,INTADR,LABINT,WORD,
& IORDER,NPQUAD,TRIANG,PROPRI,IPRINT,
& SINTMA,NCOMP,TOFILE,MTFORM,
& DOINT,EXPVAL,EXP1EL,DENMAT)
...
CHARACTER LABINT(*)*8, WORD*7, TABLE(NTABLE)*7, MTFORM*6,
& EFDIR*1, LABLOC*8
...
And this is the output I'm getting:
[xxx#yyy WORK_TEST ]$ ~/dalton/build/dalton.x
DALTON: default work memory size used. 64000000
Work memory size (LMWORK+2): 64000002 = 488.28 megabytes; node 0
0: Directories for basis set searches:
./:
LB debug, calling PR1IN1 from PR1INT
LB debug, WORD=HUCKEL
LB debug, LENGTH(WORD)= 7
At line 161 of file /p/home/lbelcher/dalton/DALTON/abacus/her1pro.F
Fortran runtime error: Actual string length is shorter than the declared one for dummy argument 'word' (6/7)
From the standard:
16.9.112 LEN (STRING [, KIND])
Description. Length of a character entity.
Class. Inquiry function.
Arguments.
STRING shall be of type character. If it is an unallocated allocatable variable or a pointer that is not associated, its length type parameter shall not be deferred.
KIND (optional) shall be a scalar integer constant expression.
Result Characteristics. Integer scalar. If KIND is present, the kind type parameter is that specified by the value of KIND; otherwise the kind type parameter is that of default integer type.
Result Value. The result has a value equal to the number of characters in STRING if it is scalar or in an element of STRING if it is an array.
Example. If C is declared by the statement
CHARACTER (11) C (100)
LEN (C) has the value 11.
16.9.113 LEN_TRIM (STRING [, KIND])
Description. Length without trailing blanks.
Class. Elemental function.
Arguments.
STRING shall be of type character.
KIND (optional) shall be a scalar integer constant expression.
Result Characteristics. Integer. If KIND is present, the kind type parameter is that specified by the value of KIND; otherwise the kind type parameter is that of default integer type.
Result Value. The result has a value equal to the number of characters remaining after any trailing blanks in STRING are removed. If the argument contains no nonblank characters, the result is zero.
Examples. LEN_TRIM (’ A B ’) has the value 4 and LEN_TRIM (’ ’) has the value 0.
I think the examples here tell the story.

Fortran EQUIVALENCE statement with array length from subroutine input

I'm modernizing some old Fortran code and I cannot get rid of an equivalence statement somewhere (long story short: it's mixed use is so convoluted it'd take too much work to convert everything).
I need the length of the EQUIVALENCEd arrays to depend on some input, like the following code:
program test_equivalence
implicit none
type :: t1
integer :: len = 10
end type t1
type(t1) :: o1
call eqv_int(o1%len)
call eqv(o1)
return
contains
subroutine eqv_int(len)
integer, intent(in) :: len
integer :: iwork(len*2)
real(8) :: rwork(len)
equivalence(iwork,rwork)
print *, 'LEN = ',len
print *, 'SIZE(IWORK) = ',size(iwork)
print *, 'SIZE(RWORK) = ',size(rwork)
end subroutine eqv_int
subroutine eqv(o1)
type(t1), intent(in) :: o1
integer :: iwork(o1%len*2)
real(8) :: rwork(o1%len)
equivalence(iwork,rwork)
print *, 'LEN = ',o1%len
print *, 'SIZE(IWORK) = ',size(iwork)
print *, 'SIZE(RWORK) = ',size(rwork)
end subroutine eqv
end program test_equivalence
This program will create 0-length arrays with gfortran 9.2.0. This is the output:
LEN = 10
SIZE(IWORK) = 0
SIZE(RWORK) = 0
LEN = 10
SIZE(IWORK) = 0
SIZE(RWORK) = 0
The same code will return Array 'rwork' at (1) with non-constant bounds cannot be an EQUIVALENCE object when compiled with gfortran 5.3.0, the warning disappears since gfortran 6.2.0, but the size of the arrays is always 0. So maybe compiler bug?
The source code is indeed not a valid Fortran program. To be specific, it violates the numbered constraint C8106 of Fortran 2018:
An equivalence-object shall not be a designator with a base object that is .. an automatic data object ..
Being a numbered constraint, the compiler must be capable of detecting this violation. If hasn't such a capability this is a deficiency in the compiler (a bug). Being "capable" doesn't mean doing so by default, so please look carefully to see whether there are options which do lead to this detection. Someone familiar with the internals of GCC can give further detail here.
As the source isn't a valid Fortran program, the compiler is allowed to consider the arrays of size zero if it has skipped the violation detection.

Display arbitrary length formatted string using IM_FORM in the Fortran FMZM multiple precision library

I'm looking at the documentation for FMZM here, and from section 8.(c), I understand that:
(c) Subroutine FM_FORM does similar formatting, but we supply a character string for
the formatted result. After declaring the strings at the top of the routine, as with
CHARACTER(80) :: ST1,ST2
the WRITE above could become
CALL FM_FORM('F15.6',H,ST1)
CALL FM_FORM('E15.7',T,ST2)
WRITE (*,"(' Step size = ',A,' tolerance = ',A)") TRIM(ST1),TRIM(ST2)
FM_FORM must be used instead of FM_FORMAT when there are more than 200 characters
in the formatted string. These longer numbers usually need to be broken into several
lines.
I need to use the IM_FORM function to display big integers longer than 200 characters. In my case, substituting IM_FORM for FM_FORM above.
Following this example, I see a declaration for:
character(200) :: str
and some clever formatting:
str = IM_format( 'i200', result ) !<----- convert BigInt to string
print *, n, trim( adjustl(str) ) !<----- print huge integers
This is great when I know my output is less than 200 characters long. However, as I'm working with an arbitrary precision library, there are good odds I may have numbers substantially larger.
So working form something like:
character(2000) :: str
res = mygetlargenumberfunction(n)
call im_form('i2000', res, str)
How can I declare my character(?) :: str variable and my IM_FORM format such that I can accomodate potentially substantially larger output unknown at compile-time? Am I left to simply guess a very large number?
Update addressing comments
I'm addressing both the allocation and the format string in the context of the FMZM arbitrary precision library, which is how it is not related to the question it is flagged as a duplicate of.
Changing
character(2000) :: str
to
character (len=:), allocatable :: str
all other things being equal, produces
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
...
Segmentation fault (core dumped)
So this suggestion appears incompatible with FMZM.
Using gfortran -std=f2008 myprogram.F90 and
GNU Fortran (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
From #francescalus's nudge, I solved the problem this way:
!
character (len=:), allocatable :: str
character(len=1024) :: fmat
!
res = mygetlargenumberfunction(n) ! call the function
lenr = log10(TO_FM(res))+1 ! size the string
allocate(character(len=lenr) :: str) ! now allocate the string itself
write (fmat, "(A5,I0)") "i", lenr ! create the format string
call im_form(fmat, res, str) ! do the call
print*, trim( adjustl(str))

Trouble with declaring a Fortran Function that returns a list [duplicate]

This question already has an answer here:
Function in fortran, passing array in, receiving array out
(1 answer)
Closed 4 years ago.
INTEGER FUNCTION NUMTOLIST(NUM) RESULT(LI)
IMPLICIT NONE
! FUNCTION TO CONVERT NUMBERS INTO ARRAYS OF NUMBERS, BY DIGIT
! PROBLEM 1: X IS NOT BEING PASSED
INTEGER :: NUM
INTEGER :: I,J
INTEGER :: LI(0:5) ! G95 COMPILER SAYS THAT 'LI ALREADY HAS BASIC TYPE INTEGER', DOESN'T RECOGNISE AS ARRAY
PRINT *,'NUM: ',NUM ! DEBUGGING LINE, CONFIRMS THAT X IS NOT BEING PASSED INTO THE FUNCTION
DO I = 0,5
J = 0
DO WHILE (J*10**(5-I)<=NUM)
J = J+1
END DO
J = J-1
LI(I) = J
NUM = NUM-(J*10**(5-I))
END DO
PRINT *,'LI: ',LI ! DEBUGGING LINE, SHOWS THAT FUNCTION IS AS IS SUPPOSED TO, EXCEPT FOR ON SOME SORT OF DEFAULT INTEGER
RETURN
END FUNCTION NUMTOLIST
PROGRAM NUMTOLISTTEST
IMPLICIT NONE
INTEGER FUNCTION, NUMTOLIST
INTEGER :: X
INTEGER :: F(1:6)
READ *,X
PRINT *,X
F = NUMTOLIST(X)
! PROBLEM 2: THE RESULT OF NUMTOLIST SHOULD BE A LIST, BUT F IS JUST BEING ASSIGNED NUM, NOT THE OUTPUT OF NUMTOLIST
PRINT *,F
READ *,X
END PROGRAM NUMTOLISTTEST
Here is my full code. As the name suggests, this is a test for a function of a larger code. There are several problems but the one that is most pressing is that for some reason a variable is not being passed to a function. I am using the silverfrost compiler, and for some reason although everything in the function itself is working as it should, it neither inputs nor returns properly. The input itself is completely disregarded, leading to num being undefined, and the return isn't being read as a list type, as F, when printed, is a list of the arbitrary number num took on. It's completely beyond me why any of this is happening, and I've been on and off looking at this for a couple of days.
Much more trivially, when I try to compile using G95, it won't. It claims that 'Li already has basic type 'Integer'', and then won't recognise Li as a list. The method I'm using to declare an integer as a list has worked in the past for me, and fits the documentation I've seen, so I'm confused why it's throwing an error.
I've been stuck on this for a while, and I just can't seem to fix it on my own. Whatever help is offered will be greatly appreciated, and thank you in advance.
You are indeed declaring a type for the variable LI twice in the function. Look:
INTEGER FUNCTION NUMTOLIST(NUM) RESULT(LI)
! (...)
INTEGER :: LI(0:5)
Notice the INTEGER keyword before function declaration. It applies to the variable name declared as result in result(LI). The second declaration of LI gives the error.
Solutions:
Remove the INTEGER from the function declaration (preferred);
Remove the second type declaration of LI. You can specify a dimension without type declaration, with the dimension specification statement.
like this:
DIMENSION LI(0:5)
Besides that, to call a function with an array as a returning value, you will need an explicit interface.

Whats wrong with the following FORTRAN 77 code?

I am a total FORTRAN 77 newbie, and I don't understand why the first code shows an error while the second one compiles when I expect them to do the same.
First code (which doesn't compile and gives a error citing an unexpected data declaration statement at z):
program FOO
integer x, y
x = 1
y = 2
integer z
z = 3
end
This code which looks 100% similar in functionality to the first one compiles without errors
program FOO
integer x, y, z
x = 1
y = 2
z = 3
end
I also tried disabling implicit variable declarations in the first code with no effects.
Fortran is one of those quaint "define everything at the top" languages. In other words, this would be fine:
program FOO
integer x, y
integer z
x = 1
y = 2
z = 3
end
since all type specifications are before any executable code. If you're going to define a variable, you should define it first. See here for example:
Such non-executable statements must be placed at the beginning of a program, before the first executable statement.
I don't know real solution but maybe fortran77 doesn't support any code between variables.
for example;
integer x, y, z
x = 1
y = 2
z = 3
works but
integer x, y
x = 1
y = 2
integer z
z = 3
doesn't work. Because between two integer definening (integer x, y and integer z ), there are variables assigning.
#paxdiablo: you think right!
and the errormessage:
"... unexpected data declaration statement at ..."
all DELCARATION must be made BEFORE the first STATEMENT occurs. fortran77 is really "old", I´m not shure if this is changed in F95
For your information: Disabling implicit variable declarations simply removes Fortan's ability to make assumptions about what type your variables are.
Implicit variable declaration makes the following assumptions: Any variable beginning with (capital or lowercase): I, J, K, L, M, or N is to be INTEGER. Any variable beginning with any other letter (capital or lowercase) is to be REAL. This applies only to variables which do not have an explicit type declaration.
You could write:
program FOO
ijk
ifjkask
end
and ijk and ifjkask would be INTEGER values.