11
votes

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?

1
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
@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
"When I today read the C Standard" <- Do you usually read the C standard in the morning or at night? (173k rep, sigh...) - user529758
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
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

1 Answers

1
votes

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.