11

When I today read the C Standard, it says about side effects

Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects

and the C++ Standard says

Accessing an object designated by a volatile glvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects

Hence because both forbid unsequenced side effects to occur on the same scalar object, C allows the following, but C++ makes it undefined behavior

int a = 0;
volatile int *pa = &a;

int b = *pa + *pa;

Am I reading the specifications correctly? And what is the reason for the discrepancy, if so?

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 2
    I don't think that there is a discrepancy. For C the type of the object is the type through which the object is read, not the type an object originally has been declared. So `*pa` is an lvalue designating a `volatile` qualified object. – Jens Gustedt Oct 14 '12 at 10:23
  • @JensGustedt i was assuming it refers to the concept of "effective type". Which for an object with a declared type is defined to be that declared type. So for the access "*pa", its effective type is "int" here unless I'm missing something. – Johannes Schaub - litb Oct 14 '12 at 10:25
  • 13
    "When I today read the C Standard" <- Do you usually read the C standard in the morning or at night? (173k rep, sigh...) –  Oct 14 '12 at 10:28
  • @H2CO3 i was [fixing wikipedia](http://en.wikipedia.org/wiki/Special:Contributions/Litb) and wanted to get a C Standard ref :) – Johannes Schaub - litb Oct 14 '12 at 10:29
  • 1
    Ah.. fixing wiki's Comp-Sci articles on variable volatility. Cause just reading the C-standard would be weird, but doing so to update wiki-comp-sci articles is much more...normal? =P Btw. great question. – WhozCraig Oct 14 '12 at 10:38
  • 1
    Yes, right, the effective type here is `int`. Interestingly if you would have used `volatile int *pa = calloc(sizeof *pa, 1);` the effective type would volatile. – Jens Gustedt Oct 14 '12 at 11:45
  • Another thing that comes to mind is that after `int i = 0; int b = i++ + i++; // i = 2 now`, but `volatile int i = 0; int b = i++ + i++; // i = 1 now`. I believe that all operations on a `volatile` operand are pooled together across a single assignment. In C++ this is explicitly left undefined. – Sergey L. Oct 14 '12 at 12:01
  • I do not find the words 'effective type' together in the C++ standard. Just to clarify (as it took me a while to get this just now), the `side effect` here just means that the program is *influenced* by something outside of the program flow, not necessarily that it _has_ a side effect. Reading the whole section I agree with the interpretation that this is not allowed in C++ as the program can't "wait" for the completed access from two volatile reads at the same time. (don't know about C). – Johan Lundberg Oct 14 '12 at 12:49
  • @JohanLundberg, effective type is a concept in the C standard, not C++. – Jens Gustedt Oct 14 '12 at 14:05

1 Answers1

1

I don't believe there is an effective variation between C and C++ in this regards. Though the wording on sequencing varies the end result is the same: both result in undefined behaviour (though C seems to indicate the evaluation will suceed but with an undefined result).

In C99 (sorry, don't have C11 handy) paragraph 5.1.2.3.5 specifies:

— At sequence points, volatile objects are stable in the sense that previous accesses are complete and subsequent accesses have not yet occurred.

Combined with your quote from 5.1.2.3.2 would indicate the value of pa would not be in a stable state for at least one of the accesses to pa. This makes logical sense since the compiler would be allowed to evaluate them in any order, just once, or at the same time (if possible). It doesn't actually define what stable means however.

In C++11 there is explicit reference to unsequenced oeprations at 1.9.13. Then point 15 indicates such unsequenced operations on the same operand is undefined. Since undefined behaviour can mean anything happens it is perhaps strong than C's unstable behaviour. However, in both cases there is no guaranteed result of your expression.

edA-qa mort-ora-y
  • 30,295
  • 39
  • 137
  • 267
  • 2
    sorry I dont understand this answer. – Johannes Schaub - litb Oct 14 '12 at 15:39
  • In short, there is no real difference in the standard between C and C++ regarding unsequenced access to volatiles. Neither guarantees an outcome for the calculation. – edA-qa mort-ora-y Oct 14 '12 at 16:47
  • 1
    [This answer](http://stackoverflow.com/a/11657272/15416) seems to have the relevant C11 wording: (6.5p2) "If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined." – MSalters Oct 15 '12 at 08:39
  • That's a good update. It now formalizes it is also undefined in C. So behaviour is the same in both languages now. – edA-qa mort-ora-y Oct 15 '12 at 15:57
  • @edA-qamort-ora-y : I believe the behavior has *always* been the same in both languages. The OP (Johannes) provided a couple of quotes from the standards which seem to say basically the same thing: accessing a `volatile` object from two directions at once is bad news. C11 adopts C++11's concept of sequenc *ing* (as opposed to sequence *points*), but it doesn't change the implications re UB in this case. – Quuxplusone Oct 17 '12 at 21:55