order of printf

H

happy

Please clear my one doubt

#include<stdio.h>
int main(void)
{
printf("1") + printf("2") * printf("3\n");
}

Here order of evaluation operands of + and * operators is not fixed.

But I wanted to know that during evaluating these operands (here the 3
printfs), do these printfs also print ( so
output can be different 123 or 231 etc.) or they just evaluate their
arguments i.e. "1", "2" and "3" and output
will always be 123?
 
S

Seebs

Please clear my one doubt

#include<stdio.h>
int main(void)
{
printf("1") + printf("2") * printf("3\n");
}

Here order of evaluation operands of + and * operators is not fixed.

But I wanted to know that during evaluating these operands (here the 3
printfs), do these printfs also print ( so
output can be different 123 or 231 etc.) or they just evaluate their
arguments i.e. "1", "2" and "3" and output
will always be 123?

Assume that we correct the program to:
printf("1") + printf("2") * printf("3");
printf("\n");

(Otherwise, if 3 printed first, there would be no newline after the others,
and on some systems that behaves surprisingly.)

Given this, any of the permutations are possible. My guess is that
the most common would be 123, 321, and 231.

-s
 
B

Barry Schwarz

Please clear my one doubt

#include<stdio.h>
int main(void)
{
printf("1") + printf("2") * printf("3\n");
}

Here order of evaluation operands of + and * operators is not fixed.

But I wanted to know that during evaluating these operands (here the 3
printfs), do these printfs also print ( so
output can be different 123 or 231 etc.) or they just evaluate their
arguments i.e. "1", "2" and "3" and output
will always be 123?

Absent undefined behavior or pathological cases, printf always prints.
Since stdout usually buffered, whether you see the output is
implementation defined unless the buffer is flushed.

The order of operand evaluation is unspecified. The only guarantee is
that the operands are evaluated before the operation is performed. The
three calls to printf can be performed in any of six possible
sequences.

One (unlikely if the compiler does any optimization) is
call with "1" and save return value (V1)
call with "2" and save return value (V2)
call with "3\n"
compute V2 * returned value
compute V1 + previous product
In this case your output would be "123\n".

A more likely sequence is
call with "2" and save return value (V1)
call with "3\n"
compute V1 * returned value and save (V2)
call with "1"
compute V2 + returned value
In this case your output would be "23\n1"
 
S

Stefan Ram

Barry Schwarz said:
Absent undefined behavior or pathological cases, printf always prints.
Since stdout usually buffered, whether you see the output is
implementation defined unless the buffer is flushed.

Even if it is flushed, the visibility still might not be given if
the last line is not terminated by a terminating new-line character.

»Whether the last line[ of a text stream] requires a
terminating new-line character is implementation-defined.«
(»7.19.2 Streams«)
 
B

Ben Bacarisse

Barry Schwarz said:
Absent undefined behavior or pathological cases, printf always prints.
Since stdout usually buffered, whether you see the output is
implementation defined unless the buffer is flushed.

The output /is/ flushed (in this example, at least). What is
implementation defined is the effect of a final output line with no
'\n' at the end (which is one possible outcome).

<snip>
 
K

Keith Thompson

Ben Bacarisse said:
The output /is/ flushed (in this example, at least). What is
implementation defined is the effect of a final output line with no
'\n' at the end (which is one possible outcome).

No, what is implementation defined is whether the '\n' at the end the
output is required. If the implementation says it's not required, the
output is flushed when the program terminates, and the behavior is
well defined (though what the environment does with the output might
not be). If the implementation says it is required, then the behavior
of the program is undefined, simply because the standard doesn't
define the behavior. (The implementation may, but isn't required to,
define the behavior anyway.)
 
B

Ben Bacarisse

Keith Thompson said:
No, what is implementation defined is whether the '\n' at the end the
output is required. If the implementation says it's not required, the
output is flushed when the program terminates, and the behavior is
well defined (though what the environment does with the output might
not be). If the implementation says it is required, then the behavior
of the program is undefined, simply because the standard doesn't
define the behavior. (The implementation may, but isn't required to,
define the behavior anyway.)

I am not persuaded that a program's behaviour is undefined in the
specific case where an implementation requires a newline at the end of
the output and none is present. Can you say more about why you
believe it is?

I know it is not normative, but wouldn't you expect this case to be
listed in sec. 2 of Appendix J if the intent were for such programs to
have undefined behaviour?

Your argument is that the standard does not define the behaviour, but
would say that is does. I would say that it defines the behaviour of

#include <stdio.h>

int main(void) { printf("No newline"); }

as well as it possibly can, regardless of any extra requirements that
the implementation may put on the stream.
 
K

Keith Thompson

Ben Bacarisse said:
I am not persuaded that a program's behaviour is undefined in the
specific case where an implementation requires a newline at the end of
the output and none is present. Can you say more about why you
believe it is?

I know it is not normative, but wouldn't you expect this case to be
listed in sec. 2 of Appendix J if the intent were for such programs to
have undefined behaviour?

Your argument is that the standard does not define the behaviour, but
would say that is does. I would say that it defines the behaviour of

#include <stdio.h>

int main(void) { printf("No newline"); }

as well as it possibly can, regardless of any extra requirements that
the implementation may put on the stream.

What else could it mean for an implementation to "require" the
newline to be present?

The standard allows an implementation to impose a certain
requirement, that the last line of a text stream must have a
terminating newline character. But it says nothing about how this
requirement might be enforce, or, equivalently, about what happens
if a program violates the requirement. It doesn't even say that
the resulting behavior is implementation-defined; it just fails to
define it.

I can imagine your program on such an implementation not writing
the last line, writing only a partial line, implicitly appending a
newline (because the underlying system requires it), having printf
return a negative value to indicate an error, or creating a corrupted
text file that can't be read. I see nothing in the standard that
forbids any of those behavior, or any other behavior.

Perhaps it wasn't intended to make the behavior undefined (the
omission from Annex J is telling), but in the absence of any
definition of the behavior, I'd say the behavior is undefined.

If it's defined, how would you say it's defined?
 
B

Ben Bacarisse

Keith Thompson said:
What else could it mean for an implementation to "require" the
newline to be present?

My view is that it would be up to the implementation what it means but
that that meaning is beyond the reach of the C standard. Had the
committee intended to make such situations undefined I think they
would have said so. They want to give permission for an implementation
to "mess up" in this case (provided it documents that it might) but
they don't want to say any more than that. It would have been so easy
to add another instance if UB explicitly at this point that the
absence is, to me, telling.
The standard allows an implementation to impose a certain
requirement, that the last line of a text stream must have a
terminating newline character. But it says nothing about how this
requirement might be enforce, or, equivalently, about what happens
if a program violates the requirement. It doesn't even say that
the resulting behavior is implementation-defined; it just fails to
define it.

I don't think it is so clear-cut. It fails to define the consequences
of a requirement.
I can imagine your program on such an implementation not writing
the last line, writing only a partial line, implicitly appending a
newline (because the underlying system requires it), having printf
return a negative value to indicate an error, or creating a corrupted
text file that can't be read. I see nothing in the standard that
forbids any of those behavior, or any other behavior.

I think my program must do all the things specified for a similar
program that has a putchar('\n'); after the printf except it does not
do the putchar. At least that seems to me a reasonable reading of the
standard. I agree with most of your possibilities except the last
one: "any other behaviour".

It all boils down to whether something that the implementation
requires is as significant as something the standard requires.
Perhaps it wasn't intended to make the behavior undefined (the
omission from Annex J is telling), but in the absence of any
definition of the behavior, I'd say the behavior is undefined.

If it's defined, how would you say it's defined?

By the sections covering printf, program termination and so on.
Characters are transmitted to the host environment, but because they
do not meet a requirement of the implementation, the host environment
is permitted to do pretty much anything it like with it. I don't see
that it is permitted to anything not related to that data.

I am aware that this is a less than satisfactory argument.
 
K

Keith Thompson

Ben Bacarisse said:
My view is that it would be up to the implementation what it means but
that that meaning is beyond the reach of the C standard. Had the
committee intended to make such situations undefined I think they
would have said so. They want to give permission for an implementation
to "mess up" in this case (provided it documents that it might) but
they don't want to say any more than that. It would have been so easy
to add another instance if UB explicitly at this point that the
absence is, to me, telling.

"Beyond the reach of the C standard" is *exactly* what "undefined
behavior" means. It doesn't mean that the program will misbehave in
some gruesome manner; it merely means that the standard doesn't say
how it behaves.

See also C99 4p2:

If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside
of a constraint is violated, the behavior is undefined. Undefined
behavior is otherwise indicated in this International Standard by
the words ‘‘undefined behavior’’ or by the omission of any
explicit definition of behavior. There is no difference in
emphasis among these three; they all describe ‘‘behavior that is
undefined’’.
I don't think it is so clear-cut. It fails to define the consequences
of a requirement.

It "fails to define" (i.e., leaves undefined) the consequences (i.e.,
the behavior).
I think my program must do all the things specified for a similar
program that has a putchar('\n'); after the printf except it does not
do the putchar. At least that seems to me a reasonable reading of the
standard.

That would be the required behavior for an implementation that
*doesn't* require the trailing newline.
I agree with most of your possibilities except the last
one: "any other behaviour".

But most of the possibilities I mentioned are inconsistent with what
you just said.
It all boils down to whether something that the implementation
requires is as significant as something the standard requires.


By the sections covering printf, program termination and so on.
Characters are transmitted to the host environment, but because they
do not meet a requirement of the implementation, the host environment
is permitted to do pretty much anything it like with it. I don't see
that it is permitted to anything not related to that data.

I don't see anything that says the consequences are limited to those
related to that data.

The behavior isn't unspecified, because the standard doesn't provide
two or more possibilities. It isn't implementation-defined, because
the standard doesn't require the implementation to document the
behavior, only to document whether the newline is required.
I am aware that this is a less than satisfactory argument.

Agreed. :cool:}
 
N

Nick

Barry Schwarz said:
Absent undefined behavior or pathological cases, printf always prints.
Since stdout usually buffered, whether you see the output is
implementation defined unless the buffer is flushed.

The order of operand evaluation is unspecified. The only guarantee is
that the operands are evaluated before the operation is performed. The
three calls to printf can be performed in any of six possible
sequences.

One (unlikely if the compiler does any optimization) is
call with "1" and save return value (V1)
call with "2" and save return value (V2)
call with "3\n"
compute V2 * returned value
compute V1 + previous product
In this case your output would be "123\n".

Exactly what GCC with no optimisation produces.
A more likely sequence is
call with "2" and save return value (V1)
call with "3\n"
compute V1 * returned value and save (V2)
call with "1"
compute V2 + returned value
In this case your output would be "23\n1"

GCC resolutely produces "123" for every optimisation level (-o0 to -o3).
Yes, I'm surprised too. I wondered if it was being so clever that it's
not even doing the arithmetic. I tried keeping the result (always 2 of
course) and printing it with the final \n, but it didn't alter things.
I'm not interested enough to get really clever and make the results of
the printfs beyond GCC's knowledge (using * parameters and random
strings perhaps) to see if that makes any difference.

My version of the code shown below just in case I'm being really silly:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
int x = printf("1") + printf("2") * printf("3");
printf("\t%d\n",x);
return EXIT_SUCCESS;
}
 
B

Ben Bacarisse

Keith Thompson said:
Ben Bacarisse said:
Keith Thompson said:
[...]
The output /is/ flushed (in this example, at least). What is
implementation defined is the effect of a final output line with no
'\n' at the end (which is one possible outcome).

No, what is implementation defined is whether the '\n' at the end the
output is required. If the implementation says it's not required, the
output is flushed when the program terminates, and the behavior is
well defined (though what the environment does with the output might
not be). If the implementation says it is required, then the behavior
of the program is undefined, simply because the standard doesn't
define the behavior. (The implementation may, but isn't required to,
define the behavior anyway.)

I am not persuaded that a program's behaviour is undefined in the
specific case where an implementation requires a newline at the end of
the output and none is present. Can you say more about why you
believe it is?

I know it is not normative, but wouldn't you expect this case to be
listed in sec. 2 of Appendix J if the intent were for such programs to
have undefined behaviour?

Your argument is that the standard does not define the behaviour, but
would say that is does. I would say that it defines the behaviour of

#include <stdio.h>

int main(void) { printf("No newline"); }

as well as it possibly can, regardless of any extra requirements that
the implementation may put on the stream.

What else could it mean for an implementation to "require" the
newline to be present?

My view is that it would be up to the implementation what it means but
that that meaning is beyond the reach of the C standard. Had the
committee intended to make such situations undefined I think they
would have said so. They want to give permission for an implementation
to "mess up" in this case (provided it documents that it might) but
they don't want to say any more than that. It would have been so easy
to add another instance if UB explicitly at this point that the
absence is, to me, telling.

"Beyond the reach of the C standard" is *exactly* what "undefined
behavior" means.

Yes, I expressed myself badly by making it so easy to find me saying
that!

First off, I have no argument against that "it'd not specified so it's
undefined argument". In that sense, I should stop here and accept
that you are right but I can't shake the nagging doubts. Specifically
that this case is missing from Appendix J2 and the unique wording that
is used for this instance. So the best I can do is accept that you
are right: it's undefined.

Permit me, though, to say what I think may have happened if for no
other reason than to try to explain my badly worded previous
explanations.

I think it is possible that the intent was to make this
implementation-defined but someone pointed out that this would require
the standard to list the possible behaviours so that the
implementation's choice can be documented (as per 3.4.1 and 3.4.4).
Making it explicitly undefined seemed rather excessive so the
ingenious language of making implementation defined whether a final
newline is required was used.

<snip>
 
K

Keith Thompson

Francis Glassborow said:
Ben Bacarisse wrote:
[...]

Summary of discussion so far:

C99 7.19.2p2 says:

A text stream is an ordered sequence of characters composed into
_lines_, each line consisting of zero or more characters plus a
terminating new-line character. Whether the last line requires a
terminating new-line character is implementation-defined.

I argue that if an implementation says that the terminating new-line
is required, and a program fails to provide it, then that program's
behavior is undefined when running under that implementation. Ben
reluctantly agrees. (The quoted text was getting too long; please let
me know if this summary is inaccurate.)
I agree. This area has always made me feel a bit uncomfortable. The
added problem is what happens if a final \n is not required. One way
that the implementation can handle this is by adding one anyway. Now I
have programs (not source code but already compiled programs) which
would barf if the termination of a data file was wrong. No newline at
the end of the file is fatal and and empty line at the end of the file
also causes problems.

If the final new-line is not required, I was about to say the behavior
is specified by the portions of the standard that describe the
behavior of stdio calls. If the program doesn't write a new-line to
the stream, no new-line is written to the stream. But as I was
writing this, I went back and read the remainder of the paragraph.
It includes the following:

Data read in from a text stream will necessarily compare equal to
the data that were earlier written out to that stream only if: the
data consist only of printing characters and the control
characters horizontal tab and new-line; no new-line character is
immediately preceded by space characters; and the last character
is a new-line character.

So, regardless of whether that trailing new-line is required, if the
program doesn't provide one, the data written needn't come back
identically when it's read. An implementation *can* implicitly append
a new-line to the end of the stream if it needs to (or just because it
wants to). For example, a text file might be stored on disk in a way
that can't represent a missing trailing new-line (say, as a sequence
of fixed-length or variable-length records, where the '\n' character
is generated on input).

(On all the implementations I've used, the trailing new-line is not
required and is not implicitly generated, and a text file can end
in an unterminated line.)
That creates a portability issue for any programs I write as tools to
create the data that these third party programs will use. Of course I
have a small tool that ensures that the data files are indeed
correctly terminated but that should not be necessary and adds just
one more task that has to be carried out and makes it just a bit more
awkward for others wishing to do the same thing (it relates to
creating Bridge deals in PBN or DLM formats and so is of use to very
basic computer users preparing hands for their clubs)

The standard explicitly gives itself permission to make some
behavior undefined without saying so, just by neglecting to define
the behavior; see C99 4p2. I always find it a little disturbing
when it does so (it tends to lead to long debates like this one),
and would be more comfortable if it said explicitly that the behavior
is undefined. In fact, I think I'd like to see the phrase "or by
the omission of any explicit definition of behavior" dropped, and
all implicit undefined behavior made explicit. If the standard
neither defines the behavior for something nor says that it's
undefined, that would be an error in the standard. I understand
that this would be a significant amount of work, and since I'm not
volunteering to do it, I won't complain too loudly if it's not done.

In this particular case, it's likely that the authors didn't
actually intend to make the behavior undefined; they added some
wording to allow for odd systems that need the trailing new-line,
but didn't follow through on the consequences.

One possible "fix" for this would be to require that, if omitting the
trailing new-line would cause problems, the implementation *must*
add one (or do something that has the same effect). This wouldn't
be too difficult to implement. Keep a flag, associated with the
stream, that indicates whether the last thing written to the stream
was a new-line. If that flag is not set when the stream is closed,
write a new-line to the stream before closing it. Most systems
wouldn't even have to do this much, since they don't require the
trailing new-line.
 
S

Stefan Ram

Keith Thompson said:
One possible "fix" for this would be to require that, if omitting the
trailing new-line would cause problems, the implementation *must*
add one (or do something that has the same effect). This wouldn't

It is possible that sometimes under an implementation this might
cause »problems«, but still other times is needed under the same
implementation.

Thus, I'd leave it as it is and teach that text files should /always/
be new-line terminated in maximally portable code, and only be
non-terminated in implementation specific code, when this is needed.

BTW: Since the I/O-system of C++ is based on C I/O (as I understand
it), all of this discussion applies to C++, too. But C++ programmers
rarely appreciate the need to think about this, because material from
C90 to them appear to be somewhat far-fetched.
 
K

Kaz Kylheku

I agree. This area has always made me feel a bit uncomfortable. The
added problem is what happens if a final \n is not required. One way
that the implementation can handle this is by adding one anyway.

Only in the case that the program invoked undefined behavior by
not supplying that newline.
Now I
have programs (not source code but already compiled programs) which
would barf if the termination of a data file was wrong. No newline at
the end of the file is fatal and and empty line at the end of the file
also causes problems.

A C implementation must not add an extra blank line to the end of a
properly terminated text stream; there is no newline-related undefined
behavior then.

If the text stream is not properly terminated, it can do anything at
all. Well, don't invoke that situation!
 
K

Kaz Kylheku

No, check elsethread.

Even if the implementation has a document which says that ``a newline is
not required at the end of a text stream''. the behavior of leaving it
out is still undefined in the C language. Implementation definitions of
extended behavior don't back-propagate into the language, otherwise
we would have to come to the conclusion that, for instance,
__attribute__ ((aligned (16)) is defined in C, due being defined in
GNU C.
Again check.

You have run into some kind of library bug. Which system is this that
adds the extra newline?

I can't find anything in the C to substantiate the concern that a
conforming library may add extra blank lines to a text file if the
program hasn't invoked undefined behavior, and has obeyed certain other
restrictions on writing to a text stream:

7.19.2 Streams

...

Data read in from a text stream will necessarily compare equal to
the data that were earlier written out to that stream only if:
the data consist only of printing characters and the
control characters horizontal tab and new-line; no new-line
character is immediately preceded by space characters; and the
last character is a new-line character. Whether space characters
that are written out immediately before a new-line character
appear when read in is implementation-defined.
 
T

Tim Rentsch

Keith Thompson said:
[long message about 7.19.2p2 means undefined behavior when
a newline is not written in an implementation whose last
lines require a newline.]

Here's another point of view. There is never undefined behavior
regardless of whether a newline is written or not. Here's
paragraph 2 in 7.19.2 again:

A text stream is an ordered sequence of characters composed into
_lines_, each line consisting of zero or more characters plus a
terminating new-line character. Whether the last line requires
a terminating new-line character is implementation-defined.
Characters may have to be added, altered, or deleted on input and
output to conform to differing conventions for representing text
in the host environment. Thus, there need not be a one-to-one
correspondence between the characters in a stream and those in
the external representation. Data read in from a text stream
will necessarily compare equal to the data that were earlier
written out to that stream only if: the data consist only of
printing characters and the control characters horizontal tab
and new-line; no new-line character is immediately preceded by
space characters; and the last character is a new-line
character. Whether the space characters that were written out
immediately before a new-line character appear when read in is
implementation-defined.

What this paragraph means is

1. It's always guaranteed that reading a text stream will read
the same bytes that were written if the three conditions are
observed;

2. An implementation may also guarantee that reading a text
stream will read the same bytes that were written even if
spaces are written just before newline characters;

3. An implementation may also guarantee that reading a text
stream will read the same bytes that were written even if
characters were written on a last line but no final newline
was written;

4. Whether conditions (2) and (3) hold are each independently
implementation-defined.

The semantics of writing to a text stream is always defined -- output
is written to stream/file in question. (Similarly the semantics of
reading is always defined.) What bytes actually appear in the file
(ie, its external representation) is _not_ defined, so the Standard
needs to say what would get read in again. 7.19.2p2 is only about
when subsequent reads are guaranteed to read the same bytes as were
written, and nothing else.

Read the language in 7.19.2p2 carefully, I expect y'all will reach the
same conclusion. Note that the semantics of reading and writing are
defined in their respective sections; and that there are no 'shall'
or 'shall not' statements in 7.19.2p2 to violate (nor are there any
violated in the rest of 7.19 as far as I know).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,754
Messages
2,569,527
Members
44,998
Latest member
MarissaEub

Latest Threads

Top