Extent of the "as-if" rule

M

Michael Wojcik

Undefined behaviour if fopen() fails. Either drop the unnecessary
fclose call or execute it as part of the the if statement.

Thanks, Dan. That's what I get for not proofing before I post...
It doesn't matter, as long as the program's output is not specified by
the C language. A compiler could optimise a correct version of your
program to:

int main(void)
{
return 0;
}

without having its conformance affected (the standard doesn't guarantee
the success of *any* fopen call).

That final parenthetical clause is certainly true, and after glancing
back over section 4 of 9899-1990 I believe you're right. A conforming
implementation could optimize away the fopen call even if that would
change the program's output, since such an implementation is only
required to "accept" strictly conforming programs, and to not provide
any extensions which would alter the behavior of strictly conforming
programs.
People need to understand that certain aspects of an implementation's
behaviour are not controlled by the C language definition (consider the
same program compiled and executed under Windows).

I think the comment regarding Windows is moot. My program (after your
correction) was intended only as an example for one implementation
(which for the sake of argument I assumed was conforming; at any rate,
the example didn't rely on any non-conforming behavior by it). The
fact that on other implementations it wouldn't demonstrate a side
effect of an otherwise-inconsequential fopen is entirely beside the
point.

In short, while it might be possible to have a (not strictly)
conforming program detect the effects of optimization in a given
implementation, that apparently does not in itself alter the
conformance of that implementation.
 
J

James Kuyper

August Derleth said:
Michael Wojcik wrote: ....

Well, I suppose that your notion of `conforming' is different from my
own. ...

The relevant notion of conforming is the one defined by the standard.
Any program that is acceptable to a conforming implementation of C is
a conforming program. The C standard NEVER requires a conforming
implementation to reject any program. At worst it requires that for
some programs a diagnostic message must be produced, but even when
that applies the implementation can still accept the program.
Therefore, a conforming implementation of C could accept all possible
programs, regardless of their contents. Therefore, any possible
program, including even the text of the Declaration of Independence,
is a conforming C program. It's a pretty useless definition; like many
useless things, it was the result of political compromise.
 
J

James Kuyper

[email protected] (Michael Wojcik) wrote in message news: said:
constructs and library calls. It should be "acceptable to any
conforming implementation", which is how C90 defines conformance. It

Well, if that's what C90 said, it's been changed in C99. It now says
"a" rather than "any", which makes the definition much easier to
satisfy.
 
D

Dan Pop

In said:
Any program that is acceptable to a conforming implementation of C is
a conforming program. The C standard NEVER requires a conforming
implementation to reject any program. At worst it requires that for
some programs a diagnostic message must be produced, but even when
that applies the implementation can still accept the program.

This is no longer true in C99:

4 The implementation shall not successfully translate a
preprocessing translation unit containing a #error preprocessing
directive unless it is part of a group skipped by conditional
inclusion.

Dan
 
K

Keith Thompson

In said:
(e-mail address removed) (Dan Pop) writes: [...]
Once you activate swapping on a certain file, this file no longer has
the semantics of standard C file, even if you can access it from a C
program.

Chapter and verse, please. C99 7.9.13 describes (in deliberately
vague terms) what a "file" is. It's clear that it can be a disk file
or a device (including a terminal). I see nothing in the description,
or anywhere else in the standard, that would exclude, for example, a
disk file or device to which the Linux "swapon" command has been
applied.

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.

Connect the text stream to an active swap file and the above guarantee
is no longer satisfied by the implementation.

So anything that can be modified by an external process is not a file?

What if the OS allows the swap file to be read but not written (other
than by the kernel)? In that case, there can be no "data that were
earlier written out to that stream" (similar to a terminal). For that
matter, what if the OS doesn't allow the swap file to be opened in
text mode?
 
S

Sidney Cadot

Dan said:
Then, what does "7.19.3 Files" talk about?

Not surprisingly, it talks about files.

However, it doesn't have a lot to say about the semantics of files; most
notably, it doesn't say what "modifying a file" means.
Which means that the definition must be taken from a normative reference,
such as ISO/IEC 2382-1:1993.

Don't have that handy, I'm afraid.
Where does the standard mention that fopen in read mode affects any
"file attributes"?

Nowhere, but where does the standard (or ISO/IEC 2382-1:1993, for all I
care) define what "modifying a file" means?
Where does the standard mention anything at all about "file attributes"?

Nowhere, it seems, which is a good thing; it has no business talking
about that, has it?

However, it has no business either to implicitly preclude reading from a
file, or opening it for reading, from having a side effect. That is an
OS matter and is out-of-scope.

Best regards, Sidney
 
D

Douglas A. Gwyn

Dan said:
Connect the text stream to an active swap file and the above guarantee
is no longer satisfied by the implementation.

The C standard explicitly does not include within its scope
the effects upon files of other processes. Also, the cited
text was clearly meant as a warning about conditions under
which data read in might not exactly match data written out
due to such things as trailing-space trimming, and should
not be taken as having some deeper metaphysical meaning.
 
D

Dan Pop

In said:
[email protected] (Dan Pop) said:
In said:
(e-mail address removed) (Dan Pop) writes: [...]
Once you activate swapping on a certain file, this file no longer has
the semantics of standard C file, even if you can access it from a C
program.

Chapter and verse, please. C99 7.9.13 describes (in deliberately
vague terms) what a "file" is. It's clear that it can be a disk file
or a device (including a terminal). I see nothing in the description,
or anywhere else in the standard, that would exclude, for example, a
disk file or device to which the Linux "swapon" command has been
applied.

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.

Connect the text stream to an active swap file and the above guarantee
is no longer satisfied by the implementation.

So anything that can be modified by an external process is not a file?

Or an implementation that allows such modifications is non-conforming.

Dan
 
J

James Kuyper

This is no longer true in C99:

4 The implementation shall not successfully translate a
preprocessing translation unit containing a #error preprocessing
directive unless it is part of a group skipped by conditional
inclusion.

I'm sorry - C99 or C++ differ in that regard, and I keep forgetting
which one it is that contains that one exception. I should have
checked before I posted. Your wording implies that C90 also lacked
that exception - is that correct?
 
D

Dan Pop

In said:
Not surprisingly, it talks about files.

However, it doesn't have a lot to say about the semantics of files; most
notably, it doesn't say what "modifying a file" means.

Since a file, in the context of the standard, is an unstructured bunch
of bytes having an associated name, what could it mean?
Nowhere, but where does the standard (or ISO/IEC 2382-1:1993, for all I
care) define what "modifying a file" means?

See above.
Nowhere, it seems, which is a good thing; it has no business talking
about that, has it?

Then, they don't exist, from the point of view of standard conformance.
And something that doesn't exist cannot be modified ;-)
However, it has no business either to implicitly preclude reading from a
file, or opening it for reading, from having a side effect. That is an
OS matter and is out-of-scope.

The standard provides a complete list of actions causing side effects.
Only the side effects caused by these actions are relevant in the
context of an implementation's conformance.

Dan
 
D

Dan Pop

In said:
The C standard explicitly does not include within its scope
the effects upon files of other processes.

Where?

2 This International Standard does not specify

- the mechanism by which C programs are transformed for use by
a data-processing system;

- the mechanism by which C programs are invoked for use by
a data-processing system;

- the mechanism by which input data are transformed for use by
a C program;

- the mechanism by which output data are transformed after being
produced by a C program;

- the size or complexity of a program and its data that will
exceed the capacity of any specific data-processing system or
the capacity of a particular processor;

- all minimal requirements of a data-processing system that is
capable of supporting a conforming implementation.

Also, the cited
text was clearly meant as a warning about conditions under
which data read in might not exactly match data written out
due to such things as trailing-space trimming, and should
not be taken as having some deeper metaphysical meaning.

The cited text says exactly what it says. An implementation violating it
is, therefore, non-conforming.

Dan
 
M

Michael Wojcik

Well, if that's what C90 said, it's been changed in C99. It now says
"a" rather than "any", which makes the definition much easier to
satisfy.

You're right; it's "a" in C90 as well. My mistake.
 
K

Keith Thompson

Or an implementation that allows such modifications is non-conforming.

Most multi-user implementations allow one process (whatever that might
mean) to modify a file while another process reads it. I hardly think
that it was the intent that any such implementation is non-conforming,
or that any such file is not a file, or that such an important rule
would be expressed in a section that explicitly refers only to text
streams.

Remember that this whole discussion started from a case where the
wording of the standard probably doesn't quite express the actual
intent (regarding whether activities that cause a swap file to be
updated should be considered "updating a file", and therefore must be
treated as side effects). Citing another section that clearly was not
intended to mean what you say you think it means doesn't seem like the
best way to resolve the issue.

Probably both sections could stand to be re-worded for clarity -- but
in either case, I don't think we need to worry about implementers
following the letter, rather than the intent, of the standard.
 
M

Michael Wojcik

I'm sorry - C99 or C++ differ in that regard, and I keep forgetting
which one it is that contains that one exception. I should have
checked before I posted. Your wording implies that C90 also lacked
that exception - is that correct?

Correct. Regarding the #error preprocessing directive, C90 only
requires that the implementation "produce a diagnostic message that
includes the specified sequence of preprocessing tokens" (which
appear between the "# error" tokens and the next newline). The
implementation is free to continue processing and succesfully
translate the t.u.

--
Michael Wojcik (e-mail address removed)

Unfortunately, as a software professional, tradition requires me to spend New
Years Eve drinking alone, playing video games and sobbing uncontrollably.
-- Peter Johnson
 
S

Sidney Cadot

Dan said:
Since a file, in the context of the standard, is an unstructured bunch
of bytes having an associated name,

Chapter and verse...?

It is hardly conceivable that an "unstructured bunch of bytes" is
compatible with the standard's notion of a file (whatever this notion
may be). For one thing, the bytes will be ordered.
[...] what could it mean?

I don't know. Could you have a shot at answering your own question?
See above.




Then, they don't exist, from the point of view of standard conformance.

"Don't exist" is improper wording, I think. "cannot be relevant" would
be better.
And something that doesn't exist cannot be modified ;-)

Let's keep our eye on the ball, shall we. We both agree that files
exist. We both agree that the standard specifically names "file
modification" as a side effect. We both cannot find a definition of
"file" (or "modifying a file") in the standard.

The question whether modifying file attributes constitutes modifying a
file cannot simply be waved away by pointing out that the standard makes
no mention of file attributes.

I think it is more likely that the Standard's authors either overlooked,
or chose to ignore, this issue rather than that they made the conscious
choice of allowing conforming implementations to optimize away an
fopen() statement. The latter would have been silly in the extreme.
The standard provides a complete list of actions causing side effects.
Only the side effects caused by these actions are relevant in the
context of an implementation's conformance.

Would you agree that attempting to exhaustively list side effects is a
silly thing to do for someone writing a standard for any programming
language, if this list excludes particular types of I/O ?

Best regards,

Sidney
 
A

Al Grant

Keith Thompson said:
Chapter and verse, please. C99 7.9.13 describes (in deliberately
vague terms) what a "file" is. It's clear that it can be a disk file
or a device (including a terminal).

It's not clear why it uses these terms. It says
"If a file can support positioning requests (such as a disk
file, as opposed to a terminal)..."
This is hardly a universal truth in either case (consider OS/390).
Does the phrase in parentheses have any normative effect at all?
 
W

Wojtek Lerch

Sidney Cadot said:
I think it is more likely that the Standard's authors either overlooked,
or chose to ignore, this issue rather than that they made the conscious
choice of allowing conforming implementations to optimize away an
fopen() statement. The latter would have been silly in the extreme.

Why do you think it's such a big deal?

And what exactly do you mean by "optimize away"? On any implementation
where fopen() is defined as a macro or an inline function, there's a good
chance that significant portions of it are often optimized away. Do you
think that's wrong, too? Do you think the C standard should specify what
portions the code of fopen() must consit of, and which ones must never be
optimized out? Do you think it would be possible to specify that in a
meaningful way, without referring to details of any particular OS, and
without introducing a requirement that an OS must be a distinct part of any
conforming implementation?
 
S

Sidney Cadot

Wojtek said:
Why do you think it's such a big deal?

Believe me, I only think it's a big deal in a very relative way. I'm not
going to lose sleep over it.

However, I do feel that standards (and their wording) is important to
get right; people will /use/ these words and take the strictest possible
view while interpreting them (comp.lang.c is a prime example).

Other than that, I think it is interesting to discuss fringe issues like
these. Many will disagree, but hey, I'm not forcing anybody to read this.
And what exactly do you mean by "optimize away"?

"optimize away" === perform a transformation from a representation where
actual code would be emitted to perform the fopen() call, to a form
where it will not be emitted.
On any implementation where fopen() is defined as a macro or an inline function,
there's a good
chance that significant portions of it are often optimized away.

Well, if you define "significant" as "big". I, on the other hand, would
prefer the traditional definition of "significant", and I would hope
that a compiler does not optimize away any significant portions.
Do you think that's wrong, too?

No. I'm all for optimizing, but only if semantics are preserved.
> Do you think the C standard should specify what
portions the code of fopen() must consit of, and which ones must never be
optimized out?
No.

Do you think it would be possible to specify that in a
meaningful way, without referring to details of any particular OS, and
without introducing a requirement that an OS must be a distinct part of any
conforming implementation?

Yes. The fact that a function must be assumed to have side effects (and
cannot, therefore, be safely optimized away) could be indicated in the
standard.

Personally, I'd advocate that function could be declared 'volatile', to
indicate precisely this.

Best regards,

Sidney
 
W

Wojtek Lerch

Sidney Cadot said:
"optimize away" === perform a transformation from a representation where
actual code would be emitted to perform the fopen() call, to a form
where it will not be emitted.

I don't think the C standard requires that any actual code must be emitted
to perform function calls. I do understand what you mean in a context of a
traditional compiler where fopen() is an external function; but if you
propose adding a new requirement to the C standard, it should be described
in terms that make sense in any conceivable implementation, including
interpreters and compilers that have an inline definition of fopen(). If a
compiler transforms the inlined code of fopen() and fclose() to a form where
very little of it is left, where exactly do you propose to draw the line
between "not optimized out" and "optimized out"?
Well, if you define "significant" as "big". I, on the other hand, would
prefer the traditional definition of "significant", and I would hope
that a compiler does not optimize away any significant portions.

And what if the compiler can prove that none are significant?

....
Yes. The fact that a function must be assumed to have side effects (and
cannot, therefore, be safely optimized away) could be indicated in the
standard.

I don't think it would make sense for the standard to say that the
implementor must *assume* that the fopen() function has side effects,
without saying what side effects are required. Since it's the implementor's
job to write the compiler, the OS, the filesystem, and the library code for
fopen(), he knows whether fopen() has any side effects or not. In the cases
when he can prove that there are no side effects, why should he not let his
compiler optimize the call away?

If the same implementation also claims conformance to some other document,
for instance POSIX, then the other document's requirements may be different.
In particular, POSIX requires files to have some attributes that the C
standard never mentions, and describes how various standard C functions
should affect those attributes. But if an implementation doesn't claim
conformance to POSIX, the C standard has no business of dictating how its
fopen() should affect file attributes, even it's an implementation for an OS
that also has a different, POSIX-conforming C implementation.
Personally, I'd advocate that function could be declared 'volatile', to
indicate precisely this.

You mean, to try to convince the compiler that the function has side effects
even if the compiler can prove by looking at the function's code that it has
none? Why?
 

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,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top