Writing Binary data to console in FORTRAN

Writing Binary data to console in FORTRAN

I am trying to wrtie double numbers in binary format to console with the following code:

REAL*8 A
A = 12.54
INQUIRE(6, name = xstring)
OPEN(1,file=xstring, access='stream',action='write')
WRITE (1) A
CLOSE(1)

Do you think it is a correct code? How can I check the output on the console is a correct representation of 12.54 number in binary format? When I check the console there are bunch of signs which are not readable by human. Thanks!

16 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

What exactly do you mean by "binary format"?  What you wrote was the actual binary contents of the variable A, which would not be useful on a console. If you want the characters 1 and 0, then try this:

WRITE(1,'(B64)') A

The use of INQUIRE here is a bit odd - why not write to unit 6 directly? By using access='stream' you won't get line endings.

Retired 12/31/2016

Quote:

Steve Lionel (Intel) wrote:

What exactly do you mean by "binary format"?  What you wrote was the actual binary contents of the variable A, which would not be useful on a console. If you want the characters 1 and 0, then try this:

WRITE(1,'(B64)') A

The use of INQUIRE here is a bit odd - why not write to unit 6 directly? By using access='stream' you won't get line endings.

Thanks for your reply Steve. What I want to do is to read that number from console by another program which is wrttien in c++. Two programs are connected by pipe mechanism. For now I am wrting the actual number on the console (12.54 appreas on the console)  and reading it by the other program and it works fine. To make the write and read process faster I decided to use bianry format. The aboved mention code is suppose to write binary representation of 12.54 on the console and the other program must read it. Do you think I am doing it right? Now what appears on the console are bunch of meaningless signs!

I see.  Choosing a different form to do the writes isn't going to materially affect performance. You might want to use hex format (Z in Fortran) to make sure that you don't lose bits due to conversions to and from decimal. You can use the f format in fscanf if you precede the characters written in fortran with "0x", so your Fortran format would be ("0x",Z16.16).

Retired 12/31/2016

Quote:

? Now what appears on the console are bunch of meaningless signs!

Just as the decimal number string "12.54" would have been meaningless to even the astute Romans around 0001 AD, to those who have not acquired familiarity with the notation a binary/octal/hex representation of a real number may be "meaningless".

It is not even necessary to use file I/O to send a number from Fortran to C or vice-versa. You can call a C function from Fortran or you can call a Fortran subprogram from C. There are several chapters in the Intel Fortran compiler documentation and several example source codes which you should become familiar with before attempting to use the ideas in your code.

>>For now I am wrting the actual number on the console (12.54 appreas on the console)  and reading it by the other program and it works fine.

Can the two programs be combined into one program?

If yes, then use mecej4's suggestion of passing the values by argument (or by buffer reference).

If no, then look in MSDN as to how to:

a) construct a pipe for interprocess communication.
.or.
b) use memory mapped file.

Jim Dempsey

Can the two programs be combined into one program?

If yes, then use mecej4's suggestion of passing the values by argument (or by buffer reference).

If no, then look in MSDN as to how to:

a) construct a pipe for interprocess communication.

Thanks for your replies. But the two programs can not be combined. I am using exactly same method described in MSDN for pipe mechanism to connect two programs. I just want to know the FORTRAN part is correct. Are does meaning less signs the binary form of the number? 

 You might want to use hex format (Z in Fortran) to make sure that you don't lose bits due to conversions to and from decimal.

Steve, I have no experience in using Hex format. I just did a quick search and found out it is very complicated and actually needs to save some charachters for: Start code, Byte count,  Address and etc. The point of converting to binary form was to reduce the size of data and make the write and read process faster. But this Hex format seems to take more size than even sending actual number! Since I want to transfer very large number of data ( double percision numbers) I am looking for simplest and fastet way. Can you please help me. Thanks

No, hex is not complicated and doesn't need "start code", etc.  I am not sure what you are seeing.

The strange characters are due to the console trying to interpret the floating point binary data as if they were text characters. You can, if you want, use a normal decimal format such as E or F to convert the floating point value to decimal characters, and then an f format in fscanf in C to "read" it, but you'll be converting from binary to decimal back to binary and this conversion is usually not exact, since many binary floating values don't have exact representations in decimal.  This is why I suggested hex format - you won't lose any bits in double-conversion.

I very much doubt sending 18 characters vs. 7 or so is going to make a performance impact. If you are willing to give up on trying to display values to the console you can use your original approach, however. Just don't expect to be able to "print" the value as it is sent.

Retired 12/31/2016

If you have established a named pipe between your programs, as you mentioned that you have done, then you can transfer data to (and from) the pipe's handle using the standard readfile and writefile functions.  This is the simplest and fastest possible block transfer, with absolutely zero in the way of formatting or any data transformations.  WriteFile() is very direct from IVF, and contains everything you want:

IF (WriteFile (ihandl,            &  ! file handle
               loc_pointer,        &  ! address of data
               nbytes,            &  ! byte count to write
               LOC(nact),        &  ! actual bytes written
               NULL_OVERLAPPED) == 0) THEN
      ! do something about error writing file 
 END IF

Thanks Steve. Very useful information. 

If you are willing to give up on trying to display values to the console you can use your original approach, however. Just don't expect to be able to "print" the value as it is sent.

I do not need to display the actual number on the console.it is just an internal process to send data to the other program. The only ipmortant thing is that the oterh program can read those data from console correctly. 

Based on what you said my original method must work fine and I have to just read those meaning less signs with my C++ program and convert them from binary to decimals.Am I right? 

If you are piping the data, you would use fread or something like that to read the data in from the pipe. Once read, it would be a normal double in the C code. Don't put a "console" in this data exchange. If you're doing this with redirection, rather than opening a pipe as a file, I would discourage you from this approach.

If you must use a console, or are using redirection, then you'll probably have to convert to a text representation and than from that back to binary in C.

Retired 12/31/2016

Don't put a "console" in this data exchange.

First I was using bianry files to write and read and not console. It worked fine: 

FILE* pFile;
fopen_s(&pFile, PathName.Left(PathName.ReverseFind('\\')) + "\\Fortran.bin", "rb");
fread((char*)&x,1,sizeof(double),pFile);
fclose(pFile);

But with huge number of data creating file is time consuming process.So I decided to transfer data by console and not files. Following is the read part of my C++ code:

#define BUF_SIZE 5000
BOOL bSuccess = FALSE;
char Buf[BUF_SIZE];
DWORD dwRead;
for (;;)
{
bSuccess = ReadFile( V_hChildStd_OUT_Rd, Buf, BUF_SIZE, &dwRead, NULL);
if( ! bSuccess || dwRead == 0 ) break;
}

const int nDoubles = dwRead / sizeof(double);

for (int i=0; i<nDoubles ; ++i)
{
double x = *reinterpret_cast<double*>(&chBuf[i*sizeof(double)]);
}

Note: V_hChildStd_OUT_Rd is a handle to the output of FORTRAN program.

But I can not read the numbers in my C++ program and I do not knwo why

vahid s.

I think you are not grasping what Steve and I are referring to a "pipe".

There is application command shell pipe:

Prog1 | Prog2

Which goes through a console handler (possibly simulated with file), and where the data is assumed (required) to be ASCII text. This means the character for backspace may remove data from stream, the character Enter may add Line Feed, and a whole numerous other things to your binary data.

The other "pipe" is a Win32 programming construct for inter-process communication. Look in Visual Studio Help | Index | pipe function

for starters.

A pipe like this can pass binary data (no editing) and as well be memory-to-memory transfer (bypassing disk file)

Also consult Google: CreateFile pipe

and pick "named pipe" from MSDN

This presents you with additional options (e.g. naming the pipe as opposed to passing a handle to the pipe to the "other" process).

Unfortunately MS VS Help Index no longer includes Win32 base functions like CreateFile inclusive of sub-topics like "named pipe"

Jim Dempsey

Here's a quick example I knocked up for a similar question seen elsewhere.  The OP uses C++ for his main program, but this is a Fortran forum, so we'll stick to that sand pit.  I was a little surprised this all works.  "Reopening" the console "file name" in the child is very shaky ground (what if the console doesn't have a name/multiple (separate) connections to the same file are not permitted in the standard), so its not something I'd rely on personally.

Edit to add the compile and run bits.

>ifort /check:all /warn:all /standard-semantics FortranPipeChild.f90
Intel(R) Visual Fortran Compiler XE for applications running on IA-32, Version 13.1.1.171 Build 20130313
Copyright (C) 1985-2013 Intel Corporation.  All rights reserved.
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.
-out:FortranPipeChild.exe
-subsystem:console
FortranPipeChild.obj
>ifort /check:all /warn:all /standard-semantics FortranPipeMain.f90
Intel(R) Visual Fortran Compiler XE for applications running on IA-32, Version 13.1.1.171 Build 20130313
Copyright (C) 1985-2013 Intel Corporation.  All rights reserved.
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.
-out:FortranPipeMain.exe
-subsystem:console
FortranPipeMain.obj
>FortranPipeMain.exe
total number of bytes read: 8
bytes read: 20,-82,71,-31,122,20,41,64
buffer interpreted as a REAL(8): 12.540000

Attachments: 

IanH,

Good example of unnamed pipe where child process inherits file handle for pipe by way of:

startup_info%hStdOutput = pipe_write

in parent. There are numerous other ways of passing the handle. An alternate way would be to use a named pipe.

Memory mapped file may yield the highest throughput but this comes with its own set of requirements that may be unsuitable to the applicaitons.

Jim Dempsey

Leave a Comment

Please sign in to add a comment. Not a member? Join today