Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C printf functionality in Fortran

1,369 views
Skip to first unread message

Epy

unread,
Jun 10, 2014, 6:32:25 PM6/10/14
to
Greetings all,

As an exercise in F2003 C/Fortran interoperability (and for my own use), I made myself a sort of printf-wrapper for Fortran that looks like:

CALL printf("%3d %5.2f %x \u20AC\n", [1.2345d0], [12, 345])

which gives: " 12 1.23 159 EURO" + newline

The arguments are at least a format string, and optionally a real (C_DOUBLE) array and/or integer (C_INT) array. I chose the array arguments to bypass the variable argument problem. I did not include characters/strings because of Fortran's built-in ability to concatenate strings.

The design is the simplest, which is to print characters that aren't part of a format specifier or escape sequence, unescape escape sequences, and to identify (but not error check) format specifiers and pass them to printf. There is no need to error check because if the format specifier is malformed, it will simply be printed to screen unconverted (this is the default behavior of gcc). The real error-checking is done within printf itself. Minimal error-checking is performed in the wrapper, but just to the extent that no memory violations occur and that the output agrees with how printf would treat things directly.

There is very little overhead; printing 1 to 150000 with this wrapper and printf in C directly takes around the same time (around 1.9 seconds on my home laptop). Everything current as of C99 is implemented except * width/precision, %n, and %c/%s (no need). Most notably, I've included the ability to unescape Unicode code points; they are converted to UTF-8 and putchar-ed.

Anyway, to the point, if anyone else would benefit from this, I'll put it up on GitHub and release it with either an MIT/BSD style license or as public domain. I might end up going to the next logical step, which is allowing the same functionality for file I/O, i.e. implement an fprintf-wrapper along with everything else that's needed to use C-style file I/O.

James Van Buskirk

unread,
Jun 11, 2014, 1:02:36 PM6/11/14
to
"Epy" <thatc...@gmail.com> wrote in message
news:fbceead6-4194-4c48...@googlegroups.com...

> Anyway, to the point, if anyone else would benefit from this, I'll
> put it up on GitHub and release it with either an MIT/BSD style
> license or as public domain. I might end up going to the next
> logical step, which is allowing the same functionality for file
> I/O, i.e. implement an fprintf-wrapper along with everything else
> that's needed to use C-style file I/O.

Could you explain the advantages and disadvantages of the wrapper
method compared to writing out specific interfaces for each of the
usages of printf() in a given program suing C interop and then
invoking them as a generic printf function?

--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


dpb

unread,
Jun 11, 2014, 1:16:25 PM6/11/14
to
On 6/11/2014 12:02 PM, James Van Buskirk wrote:
> "Epy"<thatc...@gmail.com> wrote in message
> news:fbceead6-4194-4c48...@googlegroups.com...
>
>> Anyway, to the point, if anyone else would benefit from this, I'll
>> put it up on GitHub and release it with either an MIT/BSD style
>> license or as public domain. I might end up going to the next
>> logical step, which is allowing the same functionality for file
>> I/O, i.e. implement an fprintf-wrapper along with everything else
>> that's needed to use C-style file I/O.
>
> Could you explain the advantages and disadvantages of the wrapper
> method compared to writing out specific interfaces for each of the
> usages of printf() in a given program suing C interop and then
> invoking them as a generic printf function?

I'd be far more pleased to have FORMAT-string compatible function from C
instead of having to deal with fprintf(), meself... :)

At one time I had written a mex-interface for Matlab doing a
trimmed-down version but seem to have lost it in the move back to the
farm and haven't had the ambition to recreate it.

--



Epy

unread,
Jun 11, 2014, 3:43:05 PM6/11/14
to
On Wednesday, June 11, 2014 10:02:36 AM UTC-7, James Van Buskirk wrote:
> "Epy" wrote in message
Backslash escape sequences are unescaped at compile time, so if you used any, they'd have to be in the C part of your code. My wrapper will unescape the characters from Fortran at runtime, e.g. turning "\n" (which in Fortran is two characters, not the '\n' in C), into a newline. The wrapper (already being written) would save you from having to set up each separate printf call possibility/combination e.g. 2 reals, 1 int, etc. Assuming you don't use any escape characters in the Fortran part of the code and you don't mind writing the interfaces each time, I suppose you wouldn't need this. The wrapper is designed to accept any number of arguments, so long as you only need to print out reals and ints:

USE fortran_printf

...

CALL printf("No args!\n")
CALL printf("Reals and ints: %i %.2e %5.2f\n", [9.876d0, 54.321d0], [111])
CALL printf("Reals only 45.7%%: %2.1f%%\n", [45.678d0])
CALL printf("Ints only 777 54321: %o %d\n", [511, 54321])
CALL printf("Hex test: \x54\x00045\xaDeF53\x54\x54321\n") ! hex escape sequences unescaped by wrapper

JWM

unread,
Jun 11, 2014, 3:56:21 PM6/11/14
to
On Wed, 2014-06-11 at 12:43 -0700, Epy wrote:
>
> Backslash escape sequences are unescaped at compile time, so if you used any, they'd have to be in the C part of your code. My wrapper will unescape the characters from Fortran at runtime, e.g. turning "\n" (which in Fortran is two characters, not the '\n' in C), into a newline. The wrapper (already being written) would save you from having to set up each separate printf call possibility/combination e.g. 2 reals, 1 int, etc. Assuming you don't use any escape characters in the Fortran part of the code and you don't mind writing the interfaces each time, I suppose you wouldn't need this. The wrapper is designed to accept any number of arguments, so long as you only need to print out reals and ints:


Wouldn't it be better to just provide a procedure that handles escape
characters in any string? That way it could also be used with g_vprintf,
g_vfprintf and so on.

Epy

unread,
Jun 11, 2014, 4:09:41 PM6/11/14
to
If I were to expand this module for things other than just printf, that would be one thing I'd do yes is to separate the escaping to a separate function.

Epy

unread,
Jun 11, 2014, 4:13:43 PM6/11/14
to
On Wednesday, June 11, 2014 12:56:21 PM UTC-7, jwm wrote:
As just something to share, I suppose I could translate the unescaping part to pure Fortran so that people could use escape characters without having to use the non-standard -fbackslash option from gfortran. The intent here though is to be able to use printf-style format strings to print things to the screen (since I'm more used to them and I like them better), and to be an out of the box solution so that all you have to do is use the module (no interface writing required).

glen herrmannsfeldt

unread,
Jun 11, 2014, 4:35:54 PM6/11/14
to
Epy <thatc...@gmail.com> wrote:

(snip, someone wrote)

>> 6.0134700243160014d-154/),(/'x'/)); end

> Backslash escape sequences are unescaped at compile time,
> so if you used any, they'd have to be in the C part of your
> code. My wrapper will unescape the characters from Fortran
> at runtime, e.g. turning "\n" (which in Fortran is two characters,
> not the '\n' in C), into a newline. The wrapper (already being
> written) would save you from having to set up each separate
> printf call possibility/combination e.g. 2 reals, 1 int, etc.

Some Fortran compilers will accept and process C backslash escapes.

The Java System.out.format() method, which otherwise looks very much
like C's printf, uses %n to generate a new line. On unix systems,
it will output "\n" but on DOS/Windows "\r\n".

-- glen

JWM

unread,
Jun 11, 2014, 5:09:56 PM6/11/14
to
On Wed, 2014-06-11 at 13:13 -0700, Epy wrote:
> As just something to share, I suppose I could translate the unescaping part to pure Fortran so that people could use escape characters without having to use the non-standard -fbackslash option from gfortran. The intent here though is to be able to use printf-style format strings to print things to the screen (since I'm more used to them and I like them better), and to be an out of the box solution so that all you have to do is use the module (no interface writing required).

To me it's always been the opposite: the *printf functions seem like an
ugly hack to me, whereas Fortran's format is far more elegant ---and of
course, list-directed I/O is a nice one to have.

--
John.

Epy

unread,
Jun 11, 2014, 5:27:35 PM6/11/14
to
I just like being able to do "\nNewline" instead of CHAR(10)\\"Newline", or as glen pointed out, sometimes CHAR(13)\\CHAR(10)\\"Newline"

glen herrmannsfeldt

unread,
Jun 11, 2014, 5:31:58 PM6/11/14
to
JWM <jwmw...@gmail.com> wrote:

(snip on a Fortran version of C's printf)

> To me it's always been the opposite: the *printf functions seem
> like an ugly hack to me, whereas Fortran's format is far more
> elegant ---and of course, list-directed I/O is a nice one to have.

Hmm. Having worked some years with each, and being able to convert
back and forth pretty easily, I think I like printf a little better.

For the cases mixing descriptors and text closely, it takes a
lot less writing. Well, with non-advancing I/O Fortran gets a
little closer, but:

write(*,1) (A(I),I=1,10)
1 format('A=(',F10.3,9(', ',F10.3),')')

printf("A=(%10.3f",A[0]);
for(i=1;i<10;i++) printf(", %10.3f",A[i]);
printf(")\n");

and note that the Fortran version works only for a constant array
size, where the C version is variable (as long as it fits on
one line).

And, for the Java version:

System.out.format("A=(%10.3f",A[0]);
for(i=1;i<10;i++) System.out.format(", %10.3f",A[i]);
System.out.format(")%n");

(and I didn't try to compile any of them.)

-- glen

Richard Maine

unread,
Jun 11, 2014, 6:10:46 PM6/11/14
to
Epy <thatc...@gmail.com> wrote:

> I just like being able to do "\nNewline" instead of CHAR(10)\\"Newline",
> or as glen pointed out, sometimes CHAR(13)\\CHAR(10)\\"Newline"

If it takes char(13)\\char(10) you should submit a bug report to rhe
compiler vendor. The Fortran standard specifically insulates you from
that system dependency. (I think C probably does also because I seem to
recall the C interop stuff in f2003 essentially copying the C feature).

As long as you are using formatted stream output, char(10) is supposed
to be a flag to the compiler runtimes to do whatever it takes to start a
new record. That might involve literally putting the char(10) in the
file, or it might involve putting char(13)\\char(10), or on some systems
just char(13). There even exist systems where text records are
represented using a byte-count instead of a terminator character.
Regardless, the Fortran runtimes are supposed to do whatever it takes as
long as you are using formatted stream.

Now if you happen to be using unformatted stream that's a very different
matter. Unformatted stream dumps the data to the file without
modification. But if you are using unformatted stream to write text
records, well..... don't do that. Or if you have to for some reason,
then you will get stuck with the system dependencies.

--
Richard Maine
email: last name at domain . net
domain: summer-triangle

JWM

unread,
Jun 11, 2014, 6:22:30 PM6/11/14
to
On Wed, 2014-06-11 at 21:31 +0000, glen herrmannsfeldt wrote:
> JWM <jwmw...@gmail.com> wrote:
>
> (snip on a Fortran version of C's printf)
>
> > To me it's always been the opposite: the *printf functions seem
> > like an ugly hack to me, whereas Fortran's format is far more
> > elegant ---and of course, list-directed I/O is a nice one to have.
>
> Hmm. Having worked some years with each, and being able to convert
> back and forth pretty easily, I think I like printf a little better.
>
> For the cases mixing descriptors and text closely, it takes a
> lot less writing. Well, with non-advancing I/O Fortran gets a
> little closer, but:
>
> write(*,1) (A(I),I=1,10)
> 1 format('A=(',F10.3,9(', ',F10.3),')')
>
> printf("A=(%10.3f",A[0]);
> for(i=1;i<10;i++) printf(", %10.3f",A[i]);
> printf(")\n");
>
> and note that the Fortran version works only for a constant array
> size, where the C version is variable (as long as it fits on
> one line).

Interesting choice of words. The following should work just fine,
regardless of the size of the array (as long as it fits on one line, of
course):

write (*,'("A=(",*(F10.3,:,", "))', ADVANCE = 'NO')
write (*,'(")")')

Even the old way (i.e., using a huge number instead of * ) should work.

--
John

Epy

unread,
Jun 11, 2014, 6:34:28 PM6/11/14
to
This is exactly why I made this wrapper. Both of those lines look cryptic to me, especially the 2nd. Glen's printf example is immediately understandable to me and looks less cryptic to me.

glen herrmannsfeldt

unread,
Jun 11, 2014, 7:21:59 PM6/11/14
to
Epy <thatc...@gmail.com> wrote:

(snip, someone wrote)

>> To me it's always been the opposite: the *printf functions seem like an
>> ugly hack to me, whereas Fortran's format is far more elegant ---and of
>> course, list-directed I/O is a nice one to have.

(snip)

> I just like being able to do "\nNewline" instead of
> CHAR(10)\\"Newline", or as glen pointed out, sometimes
> CHAR(13)\\CHAR(10)\\"Newline"

Yes, when you mix text and format items it takes a lot less typing
to get what you want. If you want to print out numeric values
separated by commas or other text, it is pretty inconvenient to
do in Fortran FORMAT codes. For data (numeric descriptors) only,
I might have a slight preference for the Fortran way.

-- glen

glen herrmannsfeldt

unread,
Jun 11, 2014, 7:37:01 PM6/11/14
to
JWM <jwmw...@gmail.com> wrote:

(snip, I wrote)

>> For the cases mixing descriptors and text closely, it takes a
>> lot less writing. Well, with non-advancing I/O Fortran gets a
>> little closer, but:

>> write(*,1) (A(I),I=1,10)
>> 1 format('A=(',F10.3,9(', ',F10.3),')')

(snip)

>> and note that the Fortran version works only for a constant array
>> size, where the C version is variable (as long as it fits on
>> one line).

> Interesting choice of words. The following should work just fine,
> regardless of the size of the array (as long as it fits on one
> line, of course):

> write (*,'("A=(",*(F10.3,:,", "))', ADVANCE = 'NO')
> write (*,'(")")')

> Even the old way (i.e., using a huge number instead of * )
> should work.

Yes, that is why I mentioned non-advancing.

The huge number works fine, as long as you don't need to add
text after the last item, like the close parenthesis.

With the natually non-advancing C output, I find it naturally
easier to use multiple output statements. That is, I think of the
problem as separate operations, in a way that I don't for Fortran
WRITE.

Well, I think that goes back to PL/I, which I started learning not
long after I started Fortran. PL/I formatted output is STREAM,
naturally non-advancing. Unformatted (binary) output is RECORD,
(using whatever record marks the file system uses).

It is interesting that PL/I STREAM was developed on a system where
the underlying file system is record oriented. It is a little more
obvious on C/unix with a character oriented file system.

-- glen

glen herrmannsfeldt

unread,
Jun 11, 2014, 7:43:32 PM6/11/14
to
Richard Maine <nos...@see.signature> wrote:
> Epy <thatc...@gmail.com> wrote:

>> I just like being able to do "\nNewline" instead of CHAR(10)\\"Newline",
>> or as glen pointed out, sometimes CHAR(13)\\CHAR(10)\\"Newline"

> If it takes char(13)\\char(10) you should submit a bug report to rhe
> compiler vendor. The Fortran standard specifically insulates you from
> that system dependency. (I think C probably does also because I seem to
> recall the C interop stuff in f2003 essentially copying the C feature).

C defaults to writing text files, where the system will put in the
appropriate line terminator. If you open with the b (binary) flag,
then it won't do that. On unix, the result is the same.

> As long as you are using formatted stream output, char(10) is supposed
> to be a flag to the compiler runtimes to do whatever it takes to start a
> new record. That might involve literally putting the char(10) in the
> file, or it might involve putting char(13)\\char(10), or on some systems
> just char(13). There even exist systems where text records are
> represented using a byte-count instead of a terminator character.
> Regardless, the Fortran runtimes are supposed to do whatever it takes as
> long as you are using formatted stream.

If you write PDF files, you can use either "\r\n" or "\n" line
termination, but you need to know which one it is using!

> Now if you happen to be using unformatted stream that's a very different
> matter. Unformatted stream dumps the data to the file without
> modification. But if you are using unformatted stream to write text
> records, well..... don't do that. Or if you have to for some reason,
> then you will get stuck with the system dependencies.

It might be better to write PDF as unformatted stream, even when it
is all text. (PDF 1.0 required only printable ASCII, space, and line
terminators, later the ability to write all bit patterns was added.)

-- glen

Ian Harvey

unread,
Jun 11, 2014, 9:48:42 PM6/11/14
to
On 2014-06-12 9:21 AM, glen herrmannsfeldt wrote:
> If you want to print out numeric values
> separated by commas or other text, it is pretty inconvenient to
> do in Fortran FORMAT codes.

CHARACTER(*), PARAMETER :: convenient_fmt_spec &
= "(*(G0,:,','))"

William Clodius

unread,
Jun 11, 2014, 10:55:15 PM6/11/14
to
Epy <thatc...@gmail.com> wrote:

> <snip> I just like being able to do "\nNewline" instead of
> CHAR(10)\\"Newline", or as glen pointed out, sometimes
> CHAR(13)\\CHAR(10)\\"Newline"
I assume you mean CHAR(13)//"Newline" etc.

Epy

unread,
Jun 12, 2014, 12:39:03 AM6/12/14
to
On Wednesday, June 11, 2014 7:55:15 PM UTC-7, William Clodius wrote:
Yes, thanks for that irrelevant comment. It's apparent how often I use string concatenation.

Wolfgang Kilian

unread,
Jun 12, 2014, 2:55:57 AM6/12/14
to
Why interface printf()? If the main program is Fortran, I'd suggest to
interface sprintf() instead and return the string to Fortran for
printing. You don't mix up the two I/O systems, and you can write to
any open I/O unit.

Even if you just want standard output, I don't think that the order of
output is well defined if both Fortran and C I/O systems are used
simultaneously.

Of course, you run into the separate issue of returning a C string to a
Fortran character variable and potential memory leaks. String handling
has become easier with the newest versions of Fortran.

-- Wolfgang

--
E-mail: firstnameini...@domain.de
Domain: yahoo

Epy

unread,
Jun 12, 2014, 12:47:54 PM6/12/14
to
This is true, I witnessed the order of execution problem using ifort. For this reason, I included a small interface and C function to fflush(stdout) so that you can flush the C I/O buffer after using printf in a loop etc.
0 new messages