Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > order of printf

Reply
Thread Tools

order of printf

 
 
Nick
Guest
Posts: n/a
 
      01-10-2010
Barry Schwarz <(E-Mail Removed)> writes:

> On Sat, 9 Jan 2010 09:02:06 -0800 (PST), happy <(E-Mail Removed)>
> wrote:
>
>>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".


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;
}
--
Online waterways route planner | http://canalplan.eu
Plan trips, see photos, check facilities | http://canalplan.org.uk
 
Reply With Quote
 
 
 
 
Ben Bacarisse
Guest
Posts: n/a
 
      01-10-2010
Keith Thompson <(E-Mail Removed)> writes:

> Ben Bacarisse <(E-Mail Removed)> writes:
>> Keith Thompson <(E-Mail Removed)> writes:
>>> Ben Bacarisse <(E-Mail Removed)> writes:
>>>> Keith Thompson <(E-Mail Removed)> writes:
>>>>> Ben Bacarisse <(E-Mail Removed)> writes:
>>> [...]
>>>>>> 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>
--
Ben.
 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      01-10-2010
Francis Glassborow <(E-Mail Removed)> writes:
> 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.)

>> 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.

>
> 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.

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Stefan Ram
Guest
Posts: n/a
 
      01-10-2010
Keith Thompson <(E-Mail Removed)> writes:
>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.

 
Reply With Quote
 
Kaz Kylheku
Guest
Posts: n/a
 
      01-10-2010
On 2010-01-10, Francis Glassborow <(E-Mail Removed)> wrote:
> 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!
 
Reply With Quote
 
Kaz Kylheku
Guest
Posts: n/a
 
      01-11-2010
On 2010-01-10, Francis Glassborow <(E-Mail Removed)> wrote:
> Kaz Kylheku wrote:
>> On 2010-01-10, Francis Glassborow <(E-Mail Removed)> wrote:
>>> 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.

>
> 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.

>> 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!

>
> 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.
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      01-13-2010
Keith Thompson <(E-Mail Removed)> writes:

> [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).
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
printf affects following printf/s azza C Programming 0 10-17-2010 09:43 AM
Extracting printf(...) from (void) printf(....) guru Perl Misc 8 02-03-2009 10:37 PM
the order of printf parameter marsarden C Programming 6 01-16-2006 08:44 AM
(void) printf vs printf whatluo C Programming 29 09-08-2005 05:42 PM
bus error with printf line included, error without printf line? ben C Programming 4 06-26-2004 04:42 PM



Advertisments