Sidney Cadot said:
....
I didn't mean to mandate a classic "jump to subroutine" or something
like that; the notion I try to convey is that the OS specific part
should not be optimized away if it cannot be proven it has no side
effects. However, this hinges more on the definition of side effects
than on anything else.
The C standard doesn't know the concept of the "OS specific part". It's all
just "the implementation". If the OS knows that something can be optimized
away, the implementation knows that it can be optimized away. How much of
that knowledge is made available to the compiler, on an implementation that
has a compiler, is an implementation detail that the C standard shouldn't be
concerned about.
If you don't like the term "side effects", perhaps we could call it
"required behaviour". The C standard requires that implementations behave
in a way that the C standard describes as required behaviour. Since the C
standard doesn't talk about file attributes, it neither requires nor forbids
fopen() to modify any attributes that files may have on some
implementations. On an implementation that does have file attributes, it's
up to the implementation to define how fopen() affects them, and to make
sure that it indeed affects them that way. I really can't understand why
you think it's silly that the C standard chooses not to mention that on an
implementation that defines how fopen() affects file attributes, fopen()
must affect them the way the implementation defines it. I think it would be
silly if it did.
....
My point is that for something like fopen(), the compiler can never be
able to prove this, unless it is given extra assumptions.
You keep making the distinction between the compiler and the rest of the
implementation. That distinction does not exist in the C standard. The
compiler, in an implementation that has a compiler, is free to know as much
about the rest of the implementation as its authors want it to, and
therefore doesn't need to make any extra assumptions. If a call to fopen()
isn't required to produce any significant effects in some detectable
situations, the implementor is free to write a compiler that detects those
situations and optimizes those calls away. I really don't understand why
you think that allowing this freedom to the implementor is a bad idea.
The C standard (erroneously, I think) provides those extra assumptions
by giving a list of cases it calls "side effects". If none of these
cases is relevant, the compiler may optimize at will.
Sure, but it's not *required* to optimize. If an implementor wants to have
a filesystem that guarantees that any successful call to fopen() changes
some attributes of a file, then even though the C standard doesn't refer to
those attribute changes as "side effects" and doesn't require them, he's
free to make his implementation behave that way. Of course, that means that
he'll have to make sure that his compiler doesn't optimize away the part of
fopen() that makes his implementation behave that way. Otherwise, the
implementation would break its own promise that calling fopen() changes the
attributes. But I don't think it makes sense to complain that the C
standard doesn't say that implementations are required to keep their own
promises.
By this rule, and given a strict interpretation of the rules, it is
permissible for a C compiler to optimize away fopen() here:
#include <stdio.h>
int main(void)
{
fopen("somefile", "rb");
return 0;
}
... Following Mr. Pop's argument, it would even be permissible to
optimize this away if the fopen() would have a side effect (in the
traditional, non-C sense of the word) such as altering a file attribute.
Of course, provided that the implementation doesn't claim conformance to a
document that requires altering a file attribute. The C standard is not
such a document.
My point is more that the C standard should not be readable in a way
that would condone this.
One more time: why not? What kind of problems are created by condoning it?
And where exactly do you want to draw the line?
On a typical POSIX system, writing data to a file causes the file's
attributes to be modified, and also causes the data to be transmitted
through some hardware and stored on some physical media. Do you think that
the C standard should consider both those things to be "side effects" and
forbid implementations to optimize them away? Even if the file is deleted
before its contents make it to the physical disk? If not, what kind of
wording would you use to describe the difference in general terms, in a way
suitable for a language standard?
I would think that a wording can be found that satisfies all, yes.
I'm really curious what you think such wording might look like.
If not, I think it would at least be possible to do better than the
current 5.1.2.3 #2, which I think is just plain silly; it is easy to
give an example that isn't covered but should be covered (see above).
You keep complaining and calling it silly, but I still haven't seen an
explanation of why you think the standard should cover it. When I asked you
why you think it's such a big deal, your answer was that it wasn't really
such a big deal to you, personally. That's not very convincing.
....
Indeed. However, I have a hard time seeing how a compiler could prove
that fopen() is side-effect free without the Standard lending a hand, as
it does now, with its flawed attempt to define a side effect.
What kind of problems does it create?
....
Ok, but what part in POSIX specifically mandates that fopen() must not
be optimized away? It would have to specifically mention that the notion
of a file, as understood by its C compiler, is to be augmented by
considering file attributes to be covered by the phrase "modifying a
file". Basically, POSIX would need to override the C standard in this
respect.
No, POSIX has no authority to change the C standard's definition of
"modifying a file". But POSIX can, and does, add its own requirements to
the semantics of fopen(). In particular, this is what POSIX says about how
fopen() modifies the POSIX file attributes:
If mode is w, wb, a, ab, w+, wb+, w+b, a+, ab+, or a+b, and the file did not
previously exist, upon successful completion, the fopen() function shall
mark for update the st_atime, st_ctime, and st_mtime fields of the file and
the st_ctime and st_mtime fields of the parent directory.
If mode is w, wb, w+, wb+, or w+b, and the file did previously exist, upon
successful completion, fopen() shall mark for update the st_ctime and
st_mtime fields of the file. The fopen() function shall allocate a file
descriptor as open() does.