What does your compiler do with this code?

I was wondering what compilers to with the following; and, more importantly why?

program foo
  implicit none
  integer fd,i,n
  open(newunit=fd,file='test.dat',status='replace')
  do i = 1, 10
     write(fd,'(I0)') i
  end do
  rewind(fd)
  do i = 1, 5
     read(fd,*) n
     write(*,'(I2)',advance='no') n
  end do
  endfile(fd)
  close(fd)
  print *
  open(newunit=fd, file='test.dat', status='old')
  do
     read(fd,*,end=1) n
     write(*,'(I2)',advance='no') n
  end do
1 close(fd,status='delete')
  print *
end program foo

Intel OneAPI.
image

For some reason, gfortran on my computer puts the endfile after the 6th record instead of the 5th record. I don’t know why.

I have rarely used ENDFILE, but there was an argument about this a long time ago. What ENDFILE does after a WRITE is well defined for a sequential advancing write, but it is supposed to put an end-of-file (which is usually a file truncation) after the current line. After a read of 5 lines, are you at the end of line 5 or the beginning of line 6? If you are at the beginning of line 6 you should truncate to six lines, some argued. If you are at the end of line five but not on line 6 the file should truncate to five lines. This was before non-advancing and stream I/O was standard if I remember correctly, which might add another wrinkle. The concensus was that the ENDFILE should act like a CLOSE of the file at the same point would produce and so should be 5 lines; but the READ definition read and whether you could be “positioned” at end-of-file made some people convinced it should be 5. I think it should leave a 5-line file, for consistency if nothing else; but I suspect that is why gfortran leaves 6 (?)

John is getting close to an answer. The wording in the standard it (once again) vague.

12.3.4 File position
12.3.4.1 General
...
Let n be the number of records in the file.
...
If 1 <= i < n and a file is positioned within the ith record or
between the ith and (i + 1)th record, the (i + 1)th record is the
next record.

12.3.4.4 File position after data transfer

In all other cases, the file is positioned after the record just
read or written and that record becomes the preceding record.

12.8.3 ENDFILE statement

Execution of an ENDFILE statement for a file connected for sequential
access writes an endfile record as the next record of the file.

So, let <R> and </R> denote the start and end of a record, and let @ denote the current file position. One then has

<R>5</R><R>6</R><R>7</R>

After reading 5 from the file, the file position is placed after the record that contained it. So, one can have

<R>5</R>@<R>6</R><R>7</R>   or   <R>5</R><R>@6</R><R>7</R>

Both meet the criterion of 12.3.4.4. Now, 12.3.4.1 defines next record. Of the above, the former gives the next record as <R>6</R> while the latter yields <R>7</R>.

The argument is a bit more nuanced in that the file contains 5\n6\n7\n where \n is the newline character (skipping the discussion of CRLF foible) and is taken to be the end of record. If the file position after the read of 5 is after its trailing \n, then it is pointing at 6 or at least in the record containing 6.

So the argument is that

open(unit=fd)
endfile(fd)
close(fd)

should leave one full record in the file, with whatever preexisting data were there?

Whoops. I accidentally deleted my previous response.

“Yes, no, maybe” is the best response. One needs to go read 12.5.6.14 POSITION.
No data transfer has occurred, so the first record is <R>1</R> (or 1\n if you like). 12.5.6.14 states

The scalar-default-char-expr shall evaluate to ASIS, REWIND,
or APPEND.  The connection shall be for sequential or stream
access.  A new file is positioned at its initial point.
...
If the file exists but is not connected, the position
resulting from ASIS is processor dependent.  If this specifier
is omitted, the default value is ASIS.

“Initial point” is not defined and is processor dependent. This allows the file position to be @<R>1</R> (ie., the next record is the first record in the file) or <R>@1</R> (i.e, the next record is <R>2</R>).

Is the question less ambiguous if a rewind is added before the endfile?

open(unit=fd)
rewind fd
endfile(fd)
close(fd)

It is difficult to believe that such simple questions are ambiguous in a 60+ year old language.

No. The part of 15.5.6.14 that I did not quote states that REWIND will position the file at the “initial point”. If you read about what occurs during data transfer, one of the fortunate things is that it correctly position the file for a READ.

To make kargl’s program compile with g95 (which is of course pre-2008) I put in a statement fd = 66 and changed each newunit to 'unit. The result was the same as with ifort: 2 lines of 1 2 3 4 5