drjrm3
drjrm3

Reputation: 4718

Fortran macro function for literal string?

I have a sequence of subroutine calls I need to make on various datatype names. For example:

print*, 'Now giving information about Matrix1'
call mysub(Matrix1, size(Matrix1,1), size(Matrix1,2))
print*, 'About to do function on Matrix1'
call dofunction(Matrix1)
print*, 'Matrix1 is a nice matrix! Huzzah!'

print*, 'Now giving information about Matrix2'
call mysub(Matrix2, size(Matrix2,1), size(Matrix2,2))
print*, 'About to do function on Matrix2'
call dofunction(Matrix2)
print*, 'Matrix2 is a nice matrix! Huzzah!'

print*, 'Now giving information about OtherMat'
call mysub(OtherMat, size(OtherMat,1), size(OtherMat,2))
print*, 'About to do function on OtherMat'
call dofunction(OtherMat)
print*, 'OtherMat is a nice matrix! Huzzah!'

and I would like to define a macro that will take a #define value so that I can wrap this sequence of calls. For example, defining a macro mymacro, I would like to be able to call simply

mymacro(Matrix1)
mymacro(Matrix2)
mymacro(OtherMat)

to accomplish the same thing. Is this possible?

Upvotes: 2

Views: 2416

Answers (3)

innoSPG
innoSPG

Reputation: 4656

What about writing a subroutine like this:

subroutine mymacro(matrix, matrixName)
    ! declare matrix, precision should be declare somewhere as a constant
    real(precision), dimension(:,:) :: matrix
    character(*), intent(in) :: matrixname

    print*, 'Now giving information about '//matrixname
    call mysub(matrix, size(matrix,1), size(matrix,2))
    print*, 'About to do function on '//matrixname
    call dofunction(matrix)
    print*, matrixname//' is a nice matrix! Huzzah!'
end subroutine mymacro

It is not exactly the thing that will get the name of your matrix for you but close enough.

mymacro(matrix)

becomes

call mymacro(matrix,'matrix')

Not very different, don't you think?

Upvotes: 2

dwwork
dwwork

Reputation: 858

Macros themselves are not part of Fortran. They are implemented by most (if not all) compilers by just reusing the C preprocessor. I learned from here: https://gcc.gnu.org/onlinedocs/cpp/Macros.html

This might do the trick: (not tested!)

#define MYSUB(m) write(*,*) "Now giving information about ", #m;  \
                 call mysub(m, size(m,1), size(m,2) ); \
                 write(*,*) "About to do function on ",#m; \
                 call dofunction(m) ; \
                 write(*,*) #m , "is a nice matrix! Huzzah!" ;

Note that you will have to use the appropriate compiler flags to have the compiler run the preprocessor.

Upvotes: 0

Alexander Vogt
Alexander Vogt

Reputation: 18118

It took me a while to get this working for gfortran, since it doesn't support #expr.

The idea is to use ; to get multiple commands into one line. Of course, this requires to disable the usual line limit. With gfortran, this is achieved by -ffree-line-length-0.

Then, gfortran's preprocessor uses "x" instead of #s (as every other compiler does). Here is the result: it is working on ifort and gfortran:

#ifdef __GFORTRAN__

#define mymacro(x) print *, "Now giving information about ", "x" ; \
                   call mysub( x, size(x,1), size(x,2) ) ; \
                   print *, "About to do function on ", "x"; \
                   call dofunction(x) ; \
                   print *, "x"," is a nice matrix! Huzzah!"

#else

#define mymacro(x) print *, "Now giving information about ", #x ; \
                   call mysub( x, size(x,1), size(x,2) ) ; \
                   print *, "About to do function on ", #x; \
                   call dofunction(x) ; \
                   print *, #x," is a nice matrix! Huzzah!"

#endif

program main

implicit none
integer :: i(2,2)

i = 123

mymacro(i)

contains

subroutine mysub(ii, N, M)
  integer,intent(in) :: ii(:,:), N, M
  print *,'in mysub:', ii(1,1)
end subroutine

subroutine dofunction(ii)
  integer,intent(in) :: ii(:,:)
  print *,'in dofunction:', ii(1,1)
end subroutine
end program main

Upvotes: 4

Related Questions