Hello,
I want to use getarg to define a global variable in a module (afterwards I want to execute this fortran compiled program using as second argument a number (integer)). I tried:
MODULE global_vars
CHARACTER(len=3) :: BUFFER
INTEGER :: ntimes
contains
CALL getarg(2,BUFFER)
READ(BUFFER,*) ntimes
END MODULE global_vars
but this fails given a message:
fortcom: Error: /dirX/program.f90, line 66: The statement following a CONTAINS is not a function-stmt or a subroutine-stmt.
CALL getarg(2,BUFFER)
why is this the case, and how to bypass this?
Thanks for any help.
davekw7x
08-25-2008, 03:12 PM
I want to use getarg to define a global variable in a module...
fortcom: Error: /dirX/program.f90, line 66: The statement following a CONTAINS is not a function-stmt or a subroutine-stmt.
CALL getarg(2,BUFFER)
.
Modules can contain variables and functions and subroutines, not just any old code. How would your main program invoke that code unless the code appeared in a subroutine or function that was contained in the module?
I'm not sure what you have in mind (getarg() is a built-in function; it doesn't define anything), but here's something to try. It works for me with GNU gfortran (Version 4.1.2)
MODULE global_vars
CHARACTER(len=3) :: buffer
INTEGER :: ntimes
END MODULE global_vars
PROGRAM test_globals
USE global_vars
write(*, '("Number of arguments = ",I0)') iargc()
if (iargc() .lt. 2) goto 998
call getarg(2,buffer)
read(buffer,*, ERR=999) ntimes
write(*,'("ntimes = ", I0)') ntimes
stop
998 print *,"Insufficient input."
stop
999 print *,"Bad input."
END PROGRAM test_globals
Here are a few runs:
$./test_globals
Number of arguments = 0
Insufficient input.
$./test_globals 111111 222222 333333
Number of arguments = 3
ntimes = 222
$./test_globals 11z 22 333
Number of arguments = 3
ntimes = 22
$./test_globals 11 22.2 33
Number of arguments = 3
Bad input.
Regards,
Dave
The main idea is to use a script that feeds a variable through execution of this fortran executable, something like:
execute fortran_file arg1 arg2
where arg1=filename
and arg2=ntimes (a number)
I want to define ntimes in a general way, so everywhere in the program it can be used. I thought making a module would be a neat way, but I guess this is harder as I thought.
I can do it in the way you suggested, but since I also use ntimes in subroutines, it would be more practical to create a global variable ... otherwise I would have to CALL getarg in all subroutines as well.
Any suggestion would be great.
Thanks.
Tim
davekw7x
08-26-2008, 10:01 AM
... it would be more practical to create a global variable ...
Any suggestion would be great.
The traditional way to make global variables in Fortran (when it was spelled FORTRAN, and didn't have numbers like II, IV, 77, 90, etc.) was to use common blocks. Use of named blocks could make selectively "global" variables that were available in any subprogram that used that named block.
Use of a module can make variables that are "somewhat global" in a way similar to the methodology of using common blocks. That is, the variables are available to any subprograms that use that module. So you could have a function or subroutine (that uses that module) read in the variables and go from there.
Modules can also contain subprograms that will be available to any other part of the program that uses that module. By compiling modules separately, they can be linked with other parts of programs under development without having to recompile the module each time.
Whether you use common blocks of modules to give you "global" variables, I offer the following opinion:
Gratuitous use of global variables, in general is frowned on (by many programmers and analysts) in modern times.
Here's the drill:
Pass variables to subprograms as parameters.
Declare everything explicitly in each part of the program.
Among other things, this makes debugging more straightforward, since it decreases the likelihood that simple typos (misspelling variable names in subprograms, for example) can cause disastrous side effects.
It's just an opinion. Some still cling to the mid-20th-century notion (when mainframes had a few tens of thousands of words of memory and CPU instruction cycle times were measured in microseconds) that using globals is, somehow, more "efficient" than passing parameters.
For an example without globals:
FUNCTION getinputs(iname, inumber)
IMPLICIT NONE
INTEGER :: getinputs
CHARACTER(LEN=10):: iname
INTEGER :: inumber
CHARACTER(LEN=10):: buffer
IF (iargc() .LT. 2) GOTO 998
CALL getarg(1,iname)
WRITE(*,'("getinputs: file name is ",A)') iname
CALL getarg(2,buffer)
READ(buffer,*, ERR=999) inumber
WRITE(*,'(" iterations = ", I3)') inumber
getinputs = 1
RETURN
998 WRITE(*, '(/"Insufficient input."/)')
getinputs = 0
RETURN
999 WRITE(*, '(/"Bad input."/)')
getinputs = 0
RETURN
END FUNCTION getinputs
SUBROUTINE f1(fnam, fnum)
IMPLICIT NONE
CHARACTER(LEN=10):: fnam
INTEGER :: fnum
WRITE(*,'("f1: fnam = ",A, ", fnum = ", I3)') fnam,fnum
END SUBROUTINE
SUBROUTINE f2(fname, fnumber)
IMPLICIT NONE
CHARACTER(LEN=10):: fname
INTEGER :: fnumber
WRITE(*,'("f2: fname = ",A, ", fnumber = ", I3)') fname,fnumber
END SUBROUTINE
PROGRAM test_args
IMPLICIT NONE
INTEGER :: getinputs
CHARACTER(LEN=10):: filename
INTEGER :: iterations
IF (getinputs(filename, iterations) .NE. 0) THEN
CALL f1(filename,iterations)
CALL f2(filename,iterations)
END IF
STOP
END PROGRAM test_args
Here's a run (as compiled with either GNU g77 or GNU gfortran)
$./test_args data.txt 4
getinputs: file name is data.txt
iterations = 4
f1: fnam = data.txt , fnum = 4
f2: fname = data.txt , fnumber = 4
Here's another:
$./test_args data.txt 4z
getinputs: file name is data.txt
Bad input.
I mean, there are times and places where globals may be appropriate, but...
Oh, well: Chacun Ã* son goût!
Regards,
Dave