0

I am struggling with translating a small piece of Fortran code to C. I have a file written in a binary format and a Fortran program that reads that format. My goal is to have a C program that is able to read the same format. I am completely new to Fortran and I do not have the original specification of the format. So, it is kind of a reverse-engineering process.

filename = 'file'
integer :: status
integer, parameter :: di=selected_int_kind(9)
integer(di) :: nn

OPEN(11,file = filename, status = 'old', action = 'read', form = 'unformatted', iostat = status)
if(status /= 0) then
   write(*,*) 'FILE ERROR: '//filename
   stop
endif
read(11) nn
CLOSE(11)

One thing that really confuses me is the selected_int_kind() statement. What exactly it does? What would be the equivalent in C?

Actually, my first attempt to translate was pretty much the same as the answer by @JohnBode and it did not work. It reads a totally incorrect value.

After a few more attempts I found a working solution, however, I do not understand why it is so. For some reason the correct value is written in the 5th-8th bytes. So, I can either read two int values (where the second one will be the correct one), or I can read a long value and then make a right shift for 32 bits. Any idea why Fortran can so easily retrieve the right value?

Karandash8
  • 206
  • 3
  • 7
  • 2
    See, for example, http://stackoverflow.com/q/838310 or a language/compiler reference guide. – francescalus Feb 10 '16 at 17:48
  • 1
    It wasn't clear at all. Notice the first answer which also answers about the `selected_int_kind()` function. I tried to make your problem more clear. Please do not misuse the edit as a discussion, you can place comments to your question and to the answers. If you have a problem with some code, you have to post it, otherwise the question may be closed again, for another reason. Especially, notice the comment by @francescalus about the nonexistant specification of unformated format. There will be record markers present in the file. – Vladimir F Героям слава Feb 10 '16 at 23:34
  • Actually, this recent question is very much connected, if about Python and not C. http://stackoverflow.com/questions/35319366/reading-fortran-unformatted-arrays-with-python-without-numpy – Vladimir F Героям слава Feb 10 '16 at 23:55
  • 1
    Another answer about why you are seeing extra bytes at the start (and likely at the end) of each Fortran record: http://stackoverflow.com/questions/8751185/fortran-unformatted-file-format – M. S. B. Feb 11 '16 at 04:36
  • @VladimirF thank you very much for your help! – Karandash8 Feb 11 '16 at 08:28
  • @M.S.B. thank you! It precisely explains why I have that problem – Karandash8 Feb 11 '16 at 08:30

2 Answers2

1

Types in Fortran have a KIND because the same type (INTEGER in your case) may have different "flavors" (a little like short, long, signed, unsigned, etc. in C). These kinds are integer numbers: see a list here for instance. Your expression selected_int_kind(9) means: what is the kind-number of the smallest integer kind that can contain values between -1e9 and 1e9 (see explanations here).

In C, I guess signed int should be OK because even 4 bytes (32 bits) goes from -2^31 up to 2^31-1 which is a little wider than required.

Thomas Baruchel
  • 7,236
  • 2
  • 27
  • 46
0

This is close to a 1:1 translation.

const char *filename = "file"; // or const char filename[] = "file";
long nn;

FILE *input = fopen( filename, "rb" ); // open as binary
if ( !input ) // or if ( input == NULL )
{
  fprintf( stderr, "FILE ERROR: %s\n", filename );
  exit(0);
}

if ( fread( &nn, sizeof nn, 1, input ) < 1 )
{
  fprintf( stderr, "Error while reading input\n" );
}

fclose( input );  

C doesn't have an equivalent to the "selected_int_kind" as above; instead, you would pick the appropriate type to represent the expected range of values (i.e., short, int, long, long long, etc.). If you need to be able to represent 9 decimal digits, a plain int might not be wide enough (although in practice it should be), so you should probably use long instead.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • @VladimirF: was updating my answer as you left your comment. – John Bode Feb 10 '16 at 18:24
  • The problem is that if one is to preserve the exact format of the binary file being read, `long` will be too large on Linux as `selected_int_kind()` returns the smallest integer type that can represent the requested range. – Vladimir F Героям слава Feb 10 '16 at 18:30
  • 1
    A 1-1 translation would require knowledge of the Fortran runtime that created the file. Unformatted output in Fortran does not have a single specification. – francescalus Feb 10 '16 at 18:34