I have the following FORTRAN
SUBROUTINE SETPATHS(INPUT)
!DEC$ ATTRIBUTES DLLEXPORT::SetPaths
CHARACTER*20 INPUT
CHARACTER*20 DIRECTORY
DIRECTORY = 'ABCDEFG'
WRITE(6, *) 'INPUT LEN_TRIM = ', LEN_TRIM(INPUT)
WRITE(6, *) 'DIRECTORYLEN_TRIM = ', LEN_TRIM(DIRECTORY)
END SUBROUTINE
And I'm calling the function from C#, passing in 'ABCDEFG'.
When I set a breakpoint on my debugger, INPUT and DIRECTORY have the exact same characters. Both have 'ABCDEFG' followed by the same number of trailing spaces.
However, the program outputs
INPUT LEN_TRIM = 20
DIRECTORYLEN_TRIM = 7
Is this correct behavior? If the two strings have the same values, why does LEN_TRIM give different results?
Update: I found this documented problem (although it's not my Intel 8.1 compiler). http://support.microsoft.com/kb/89131
sbo#dhcp-045:~ $ ./a.out
INPUT LEN_TRIM = 7
DIRECTORYLEN_TRIM = 7
sbo#dhcp-045:~ $ more test.f90
SUBROUTINE SETPATHS(INPUT)
CHARACTER*20 INPUT
CHARACTER*20 DIRECTORY
DIRECTORY = 'ABCDEFG'
WRITE(6, *) 'INPUT LEN_TRIM = ', LEN_TRIM(INPUT)
WRITE(6, *) 'DIRECTORYLEN_TRIM = ', LEN_TRIM(DIRECTORY)
END SUBROUTINE
program test
character*20 foo
foo = "ABCDEFG"
call setpaths(foo)
end program
What compiler are you using ? here gfortran.
Tried with ifort as well
$ ifort -v
Version 8.0
$ ifort test.f90
$ ./a.out
INPUT LEN_TRIM = 7
DIRECTORYLEN_TRIM = 7
I don't know how the C# interface can introduce problems, but the semantics of LEN_TRIM are quite easy... if you say that the strings appear as equal in the debug, there's something very fishy going on.
it may be looking for Terminator character, char(0). it could be different from \n character
other possibility the string length was not passed correctly. fortran 77 string is passed as two values, string pointer and string length. there is no standard how string length is passed, most compilers stick it as a hidden parameter in the end. could be 90 does the same thing for compatibility.
By explicitly padding my C# StringBuilder with trailing spaces, the LEN_TRIM behaved as expected. This Microsoft KB seems to be related.
It is strange, however, that in the debugger the trailing spaces appeared even before I did the explicit padding.
Related
I have a project written in VS2010 with Intel Visual Fortran. I have a dump subroutine to write a 2D matrix into file:
subroutine Dump2D(Name,Nx,Ny,Res)
implicit none
integer i,j,Nx,Ny
real(8) :: Res(Nx,Ny)
character(len=30) name,Filename
logical alive
write(filename,*) trim(Name),".dat"
Write(*,*) "Saving ",trim(Name)," Please wait..."
open (10,file=filename)
do i=1,Ny
Write(10,FMt="(D21.13\)") (Res(j,i),j=1,Nx)
Write(10,*)
end do
close(10)
Write(*,*) "Save ",trim(Name),"Complete!"
return
end subroutine Dump2D
It is ok to compile and run. But when I compile in emacs using gfortran it gives me the error:
I think it's because the gfortran doesn't recognize \ in a format for a write command. How do I fix this problem?
Write(10,FMt="(D21.13\)") (Res(j,i),j=1,Nx)
1
Error: Unexpected element '\' in format string at (1)
The edit descriptor \ relates to backslash editing. This is a non-standard extension provided by the Intel compiler (and perhaps others). It is not supported by gfortran.
Such backslash editing is intended to affect carriage control. Much as in this answer such an effect can be handled with the (standard) non-advancing output.1
As you simply want to output each column of a matrix to a record/line you needn't bother with this effort.2 Instead (as you'll see in many other questions):
do i=1,Ny
write(10,fmt="(*(D21.13))") Res(:,i)
end do
There are also other approaches which a more general search will find.
1 The Intel compiler treats \ and $ in the same way.
2 There are subtle aspects of \, but I'll assume you don't care about those.
Another approach (although francescalus answer is better in your case) would be to build a format string that contains the number of elements to include in your row. One way of doing this is to use the following to build the format string (which uses an explicit space character to separate elements within a line in the file):
WRITE(fmtString, '(A,I0,A)') '(', Nx, '(D21.13,:,1X))' *
Then use the format string variable in your WRITE statement as so:
do i=1,Ny
Write(10,FMt=fmtString) (Res(j,i),j=1,Nx)
end do
This approach can also be very useful if you want to use something other than spaces to separate elements (e.g. commas or semicolons).
*As that's a little difficult to read, I will provide an example. For Nx = 3, this would be equivalent to:
fmtString = '(3(D21.13,:,1X))'
Which is 2 numbers formatted using D21.13, each followed by a space, and a final number formatted using D21.13, but without a space after it (as the ":" stops at the final item).
The backslash is not valid in Fortran 77 FORMAT statements. Gfortran will not compile it, unless you fix the code. There is no flag that will change that AFAIK (-fbackslash should not help here).
If I understand the intention correctly (and I may be wrong), the backslash does the same as the dollar sign in some other compilers and prevents terminating a record (line). In that case the advance="no" put in the write statement should help. It is Fortran 90, but you should not avoid it just for that reason.
I'm trying to write in from fortran a text file.
I did this short test program but of course it does not work, because it does not create a text file that could be readable :
PROGRAM teste
INTEGER(4) REC2,RECL1
character(20) :: charI, wanted
RECL1=10
DO REC2=1,10
OPEN(1,FILE='teste.txt',ACCESS="direct",RECL=RECL1);
write (charI, "(A5,I4)") "hello", REC2
wanted=trim(charI)
write(1,REC=REC2) wanted
close(1)
END DO
END PROGRAM teste
I read lot of different thing but it's still really unclear how it should be written.
Do I need to convert to string before writing ? if yes why ?
Try this
PROGRAM test
IMPLICIT NONE
INTEGER, PARAMETER :: ascii = selected_char_KIND ("ascii")
INTEGER, PARAMETER :: ucs4 = selected_char_KIND ('ISO_10646')
INTEGER :: ix
CHARACTER(len=5,kind=ucs4) :: greeting = ucs4_"hello"
OPEN(10,FILE='test.txt')
DO ix=1,10
WRITE (10,'(A5,I4)') greeting, ix
END DO
CLOSE(10)
END PROGRAM test
... a commentary ...
PROGRAM test
IMPLICIT NONE
All good Fortran programs include the line implicit none; the reason for this is explained in 101 Qs and As here on Stack Overflow and I won't repeat them here.
INTEGER, PARAMETER :: ascii = selected_char_KIND ("ascii")
INTEGER, PARAMETER :: ucs4 = selected_char_KIND ('ISO_10646')
The latest Fortran standard requires that compilers provide these two kinds of character. I'm honestly not sure if iso_10646 is the same as UTF-8 but if it isn't you're probably out of luck. Here, I'm defining two parameters for identifying the character kinds to use later in the program. For your purposes the first of these parameters is unnecessary but you ought to know about it too.
I suppose your compiler might support other character kinds, read the documentation.
(Aside: technically, there is a third character kind name, default. This is likely to set the character kind to either ascii or iso_10646, most likely the former, but if this is important to you check your compiler's documentation.)
INTEGER :: ix
CHARACTER(len=5,kind=ucs4) :: greeting = ucs4_"hello"
In the second of these lines I've defined a character variable with the text hello and of kind ucs4 (which, as you see above, is a local code for iso_10646). Without the prefix ucs4_ the string hello will be interpreted as being of kind default and then converted to ucs4 when stored into the variable greeting. In this case, where there is a 1:1 mapping between the (representation of) the characters in ascii and in ucs4 the prefix is strictly unnecessary but there will be other cases where it won't be.
OPEN(10,FILE='test.txt')
DO ix=1,10
WRITE (10,'(A5,I4)') greeting, ix
END DO
CLOSE(10)
I've removed all the guff about direct access and writing at particular records in a file. It's all unnecessary for what seems to be your immediate need. So this loop will write greeting (ie the ucs4 string hello) and a row index into the file test.txt 10 times.
END PROGRAM test
In your open statement you are opening a file for unformatted input/output. Because you have specified ACCESS="direct" the default is for unformatted, compared with the default as formatted when connected for sequential access.
To make the file "readable" you need to actively open for formatted access, and provide a format for the writing:
open(1,FILE='teste.txt',ACCESS="direct",RECL=RECL1, FORM='formatted')
...
write(1,fmt=...,REC=REC2) ...
I have a project written in VS2010 with Intel Visual Fortran. I have a dump subroutine to write a 2D matrix into file:
subroutine Dump2D(Name,Nx,Ny,Res)
implicit none
integer i,j,Nx,Ny
real(8) :: Res(Nx,Ny)
character(len=30) name,Filename
logical alive
write(filename,*) trim(Name),".dat"
Write(*,*) "Saving ",trim(Name)," Please wait..."
open (10,file=filename)
do i=1,Ny
Write(10,FMt="(D21.13\)") (Res(j,i),j=1,Nx)
Write(10,*)
end do
close(10)
Write(*,*) "Save ",trim(Name),"Complete!"
return
end subroutine Dump2D
It is ok to compile and run. But when I compile in emacs using gfortran it gives me the error:
I think it's because the gfortran doesn't recognize \ in a format for a write command. How do I fix this problem?
Write(10,FMt="(D21.13\)") (Res(j,i),j=1,Nx)
1
Error: Unexpected element '\' in format string at (1)
The edit descriptor \ relates to backslash editing. This is a non-standard extension provided by the Intel compiler (and perhaps others). It is not supported by gfortran.
Such backslash editing is intended to affect carriage control. Much as in this answer such an effect can be handled with the (standard) non-advancing output.1
As you simply want to output each column of a matrix to a record/line you needn't bother with this effort.2 Instead (as you'll see in many other questions):
do i=1,Ny
write(10,fmt="(*(D21.13))") Res(:,i)
end do
There are also other approaches which a more general search will find.
1 The Intel compiler treats \ and $ in the same way.
2 There are subtle aspects of \, but I'll assume you don't care about those.
Another approach (although francescalus answer is better in your case) would be to build a format string that contains the number of elements to include in your row. One way of doing this is to use the following to build the format string (which uses an explicit space character to separate elements within a line in the file):
WRITE(fmtString, '(A,I0,A)') '(', Nx, '(D21.13,:,1X))' *
Then use the format string variable in your WRITE statement as so:
do i=1,Ny
Write(10,FMt=fmtString) (Res(j,i),j=1,Nx)
end do
This approach can also be very useful if you want to use something other than spaces to separate elements (e.g. commas or semicolons).
*As that's a little difficult to read, I will provide an example. For Nx = 3, this would be equivalent to:
fmtString = '(3(D21.13,:,1X))'
Which is 2 numbers formatted using D21.13, each followed by a space, and a final number formatted using D21.13, but without a space after it (as the ":" stops at the final item).
The backslash is not valid in Fortran 77 FORMAT statements. Gfortran will not compile it, unless you fix the code. There is no flag that will change that AFAIK (-fbackslash should not help here).
If I understand the intention correctly (and I may be wrong), the backslash does the same as the dollar sign in some other compilers and prevents terminating a record (line). In that case the advance="no" put in the write statement should help. It is Fortran 90, but you should not avoid it just for that reason.
I'm having a runtime error when I run a code that works without problems using a different computer.
I'm wondering if the problem is the Fortran compiler of this machine (GCC 4.9.2) since the former computer used a previous version.
The issue comes when defining a variable like this:
In a module I define
character(30),allocatable,save :: sceneclass(:)
Then in the subroutine sceneclass is defined according to
character(30) surf, frac, scene
allocate(sceneclass(10))
do i=1,10
write(sceneclass(i),*) trim(scene)//trim(surf)//'_'//trim(frac)
enddo
In the first iteration I get the "End of record". But I don't know where is the problem. It seems to work fine in other computers.
You are probably writing a string to sceneclass(i) that is longer then the 30 chars you specified.
I can reproduce this with
program test
implicit none
character(10),allocatable :: sceneclass(:)
integer :: i
allocate( sceneclass(10) )
do i=1,10
write(sceneclass(i),*) 10**i
enddo
print *, ( trim(sceneclass(i)), i=1,10 )
end program
gfortran fails with
Fortran runtime error: End of record
while ifort reports the error correctly:
output statement overflows record, unit -5, file Internal List-Directed Write
Increasing the string length to 12 solves the issue in this case. You can (and should) use iostat within the write statement to capture this.
One thing to be aware of, when you specify a list directed * write of a character string, the compiler always(?) adds an extra lead blank, so the effective length of the string you can write is one less than you might expect.
To remedy that (and of course assuming you don't want the lead blank anyway ) use a string edit descriptor:
write(sceneclass(i),'(a)')...
Interestingly ifort (linux 11.1) actually allows you to overrun by one character:
character*5 c
write(c,*)'12345' ! result: " 1234"
which I would consider a bug. It seems they forgot to count the blank too.. ( gfortran throws the above error on this, and ifort balks if you add one more character )
see here if you wonder why the blank.. Are Fortran control characters (carriage control) still implemented in compilers?
and now I'm curious if some compiler somewhere didn't do that for an internal list write, or maybe your code was previously compiled with a flag to disable the "printer control" code
I'm learning Fortran for a new job and started writing some very, very basic programs. To compile, I'm using gcc version 4.6.2, and I'm working on Linux Suse OS (if that matters at all). I believe the version of Fortran I'm using is F90 or F95. The code is written using the VIM text editor.
Here is the program I've written
INTEGER, PARAMETER :: x = 2, y = 3
INTEGER :: z = x+y
print *, z
That's it! Oh, and the lines are indented, They start on column 8, so indentation isn't an issue.
UPDATE 1
I have tried doing this like so:
PROGRAM print_stuff
print *, z
END PROGRAM print_stuff
I also tried adding the IMPLICIT NONE statement to all of that and didn't get a change in the error.
END UPDATE 1
I save, quit, and compile. The compiler returns this error:
Error: Unexpected end of file in 'practice1.f'
Anyone know what the problem is? I've even tried removing the print statement and just having the variable declarations but the same error occurs. It's keeping me from practicing Fortran at all!
Your first version
INTEGER, PARAMETER :: x = 2, y = 3
INTEGER :: z = x+y
print *, z
is NOT a valid Fortran program. Every valid program ends with the end statement. A 'program' without an end statement is not syntactically correct. Keep reading your introductory tutorial.
I suggest you get into the habit of starting your programs with a program statement, with a name, such as
program myprog
and ending them with
end program myprog
Strictly, neither the program statement nor a program name is necessary but they do make things look a bit more comprehensible.
Oh, and while I'm writing ... don't get into the habit of starting lines at column 8, that smacks of the now out-dated fixed-form source. If you are using a reasonable compiler (such as gcc) give your filenames the .f90 suffix and let your source code run free. All the while observing good habits of indentation of course.
EDIT in response to OP's edits
PROGRAM print_stuff
print *, z
END PROGRAM print_stuff
and
INTEGER, PARAMETER :: x = 2, y = 3
INTEGER :: z = x+y
print *, z
END
are both syntactically correct. Both gfortran (v4.1.2) and Intel Fortran (v13.0.1) compile both correctly and produce executables which execute.