Path: csiph.com!eternal-september.org!feeder.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: Default values in #define Date: Wed, 31 Aug 2016 10:29:50 -0700 Organization: None to speak of Lines: 148 Message-ID: References: <87vaystxvp.fsf@bsb.me.uk> <1d377167-a33a-402e-89ee-d3efa06d95ab@googlegroups.com> <87twebuwwn.fsf@gmail.com> <36a5bcc3-9e30-468c-a3e1-4b9c9788d395@googlegroups.com> <1Kgvz.279$6d.174@fx26.iad> <8277ffd2-121d-4f3a-9bb0-ad3068696415@googlegroups.com> <502669cd-f0fc-4b99-8c8a-0d806c8b5f20@googlegroups.com> <566c947b-91d6-43c1-86aa-772f6cf21e35@googlegroups.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: mx02.eternal-september.org; posting-host="945944de09706c9b4e29b53c9d2efdc2"; logging-data="12508"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18FCJC7L/igIxgzIG1jRpOk" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) Cancel-Lock: sha1:fhR4vmbw7SDqD/d5Yelg6U3zK3Q= sha1:xVOI8Miw2EJdNLvix5dAdkEhHhA= Xref: csiph.com comp.lang.c:92995 Tim Rentsch writes: > Keith Thompson writes: >> David Brown writes: >>> On 29/08/16 18:28, Keith Thompson wrote: >>>> David Brown writes: >>>> [...] >>>>> The C standard is weak on this area - "What constitutes an access to an >>>>> object that has volatile-qualified type" is implementation defined >>>>> behaviour. So I think your answer here is that it depends on the compiler. >>>> >>>> [...] >>>> >>>> That's not what the standard says. >>>> >>>> N1570 6.7.3p7: >>>> >>>> What constitutes an access to an object that has volatile-qualified >>>> type is implementation-defined. >>>> >>>> It's the question of whether a given operation is an access to a >>>> volatile object that's implementation-defined, not the behavior. >>> >>> That is really the question. When you make a pointer-to-volatile >>> using a cast, and access that, is it a volatile access or not? I >>> /think/ the standard says the answer is implementation-defined - but I >>> also think that compilers would treat all accesses via pointers as >>> volatile accesses. >> >> My point is that you incorrectly introduce the phrase >> "implementation defined behaviour". It's not the *behavior* that's >> implementation-defined, it's the determination of what constitutes >> an access. > > How this is phrased makes it hard to know what you mean. Let me > try to break this down, as I understand what the Standard is > saying. > > Which C constructs require a "volatile access" is exactly defined > by the ISO standard. They are precisely those expressions whose > evaluations cause an access (either reading or writing), and > whose type is volatile-qualified. This aspect is not affected > by 6.7.3p7. That's not how I interpret(ed) it. Again, here's what the standard says: N1570 6.7.3p7: What constitutes an access to an object that has volatile-qualified type is implementation-defined. Perhaps it's poorly phrased (or perhaps I'm just reading it poorly), but I've always understood that to mean that the implementation defines what is or is not an access to a volatile object. The word "access" means "to read or modify the value of an object" (the use of "access" as a noun rather than a verb follows naturally from that). The definition says it's an "execution-time action". It's stated in terms of C semantics, not whatever machine-level operations are used to implement those semantics. For a non-volatile object, an access is a read or a write. I interpreted 6.7.3p7 to give the implementation some latitude in determining what is or is not an access to a volatile object. I was (somewhat vaguely) thinking that an implementation is still allowed to optimize away some apparent accesses to volatile objects. Which, now that I think about it, doesn't make a whole lot of sense. > What is to be done to effect, or carry out, a volatile-qualified > access is what must be defined by each implementation. This > might be, eg: (a) ordinary reads and writes; (b) ordinary reads > and "cache write-through" writes; (c) atomic reads and writes, > and atomic read-modify-write for things like += or similar; or > perhaps (d) reads and writes with memory barriers before and > after. (This list is not meant to be exhaustive.) This aspect, > "how a volatile-access is to be carried out", is exactly what an > implementation must define (and document) under 6.7.3p7. > > The Standard isn't very good at spelling this out, but discussion > in the Rationale document makes it all fairly clear (as usual, > IMO). Now that I think about it, your interpretation makes more sense than mine (though I still think mine is more strongly suggested by the wording). As you point out, the Rationale is clear on this: No cacheing through this lvalue: each operation in the abstract semantics must be performed (that is, no cacheing assumptions may be made, since the location is not guaranteed to contain any previous value). though it doesn't discuss the implementation-defined something-or-other of 6.7.3p7. Perhaps the word "constitutes" is the problem? So the idea is that the implementation must document *what happens* when a volatile object is accessed. (And any such documentation would have to be in terms of low-level semantics, below the usual level of the abstract machine.) The gcc documentation says (I'm paraphrasing here) that given volatile SOME_TYPE *v = SOME_VALUE; *v; the expression `*v` may or may not read the volatile object, depending on its type. That's consistent with my previous reading of 6.7.3p7, but not with yours. >> Once that's determined, the behavior might be either >> well defined, implementation-defined, unspecified, or undefined, >> depending on the specific code. > > To me this just seems wrong. What is to be done is determined by > an implementation-defined statement. The Standard requires that > this action, whatever it is, be carried out. The /consequences/ > of carrying out said action may be unbounded, but that is not the > same as undefined behavior. For example, `*v` where v is a null pointer has undefined behavior, as does `v` (if v itself is volatile) where v's value is indeterminate. But yes, if loading an indeterminate pointer value into a register might cause a trap, the compiler still has to generate code that actually attempts to load that value if the pointer object is volatile; it can't assume that it's indeterminate based on previous execution. >> One example of how this is defined is here (for gcc): >> >> https://gcc.gnu.org/onlinedocs/gcc-6.2.0/gcc/Qualifiers-implementation.html > > In my view what is described on that page crosses the line, at > least in spirit. Implementations are not allowed to decide which > volatile-qualified accesses will be done and which will not; > they only get to decide how a VQA is carried out. Not whether, > only how. Not doing any access at all (the text doesn't say this > outright but it is implied) is not conforming, or at least not > spirit-conforming. I think I agree. -- Keith Thompson (The_Other_Keith) kst-u@mib.org Working, but not speaking, for JetHead Development, Inc. "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"