4

I was answering a question and made this test program.

#include <stdio.h>
int main()
{
    volatile const int v = 5;
    int * a = &v;
    *a =4;
    printf("%d\n", v);
    return 0;
}

Without the volatile keyword the code optimizes (compiled with -O3 apple clang 4.2) the change of the var away, with it works as expected and the const variable is modified correctly.

I was wondering if a more experienced C developer knows if there is a part of the standard that says this is unsafe or UB.

UPDATE: @EricPostpischil gave me this standards quote

A program may not modify its own object defined with a const-qualified type, per C 2011 (N1570) 6.7.3 6: “If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.” An external agent may modify an object that has volatile-qualified type, per 6.7.3 7: “An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects

My program breaks the first rule but I thought that the second rule may exempt a program from the first.

UPDATE 2:

An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously.134) What constitutes an access to an object that has volatile-qualified type is implementation-defined.

If you look at this quote you can see the var must be evaluated according to certain rules, I haven't read through all of section 5.1.2.3 but I believe that this may shed some light on the issue.

Community
  • 1
  • 1
aaronman
  • 18,343
  • 7
  • 63
  • 78
  • I'm sure this doesn't compile without errors. – Devolus Aug 05 '13 at 18:11
  • @Devolus 1 warning, unless I left a typo in there – aaronman Aug 05 '13 at 18:11
  • @Devolus in c99 standart, there is even an example thats almost equvalent to this one, and its noted as "may break the rule" not even a "breaks the rule" if I'd remember which rule it was, id look it up for you, but I'm sorry. but i was confused too and thought, That can't be without any errors. I tryed it.... and I was wondered... MSVC2010 compiler-> no warnings, no errors clang -> no error, 1 warning about something like "acces of not quallified type" or something. and gcc had also 0W/0E. – dhein Aug 12 '13 at 11:51
  • Why would you think 6.7.3.7 has any effect on 6.7.3.6? An assignment via a pointer is not "an external agent" or "modified in ways unknown to the implementation". – Chris Dodd Feb 15 '16 at 22:12

2 Answers2

3

It is unsafe because the same behavior cannot be guaranteed for use in other compilers. So your code is compiler-dependent and may even be compiler switch dependent. That's why it's a bad idea.

Jiminion
  • 5,080
  • 1
  • 31
  • 54
  • I agree with you in some respects but I also just tested it with g++ and it exhibited my expected behavior, hopefully someone can find a compiler where it doesn't work – aaronman Aug 05 '13 at 18:16
  • That's not really the point. The point is someone could build a compiler in spec that didn't do that or allow for it. Then your code would break, perhaps sometime in the far future. – Jiminion Aug 05 '13 at 18:18
  • Yes but the point of my question is I believe even with the standards quote it is up for debate what the standard is implying, I'm not saying your wrong just that it is possible you are – aaronman Aug 05 '13 at 18:20
  • 2
    I don't see the evidence that 6.7.3.7 is an invitation to violate 6.7.3.6 – Jiminion Aug 05 '13 at 18:23
  • Well maybe you don't but I think it's possible it does, also I found a draft of the standard and I'm looking through it – aaronman Aug 05 '13 at 18:31
  • http://stackoverflow.com/questions/4592762/difference-between-const-const-volatile This indicates use of volatile const is for a variable that can change OUTSIDE of the program (such as it being tied to a hardware or other read-only device). Your code violates the spirit of that. – Jiminion Aug 05 '13 at 18:58
  • Does not fully address my question because volatile has specs on how you are allowed to modify access to the marked var, if it is impossible to write a correct compiler that behaves incorrectly in This situation than u r incorrect – aaronman Aug 05 '13 at 19:05
  • 8.7.3.6 trumps 6.7.3.7 (Note the "may be" which could also mean "may NOT be"). A compiler that followed 8.7.3.6 strictly would not violate the spec. – Jiminion Aug 05 '13 at 19:12
  • What 8.7.3.6 say, also if you look at the update not modifying the var may violate the rules of the abstract machine – aaronman Aug 05 '13 at 19:19
  • Assuming you are right, what would you do if a compiler builder thinks otherwise? You still have broken code. It's not a code idea to skate the veneer in this fashion. It doesn't serve you well, even if you are "right". – Jiminion Aug 05 '13 at 19:33
  • Please its a question of interest i would never use this, im more of a cpp guy – aaronman Aug 05 '13 at 19:38
  • @Jiminion: If `v` were an external or exported symbol and all accesses to it were through `volatile`-qualified pointers, would argue that the intended spirit of the Standard would suggest that a compiler for most platforms should presume that the programmer knows something about the hardware the compiler doesn't, and should perform a store to the indicated address and let whatever happens as a result, happen. The authors of the Standard recognized that on some platforms it may make sense to treat things differently, which is why they left behavior undefined, ... – supercat Feb 19 '17 at 01:02
  • ...but the Standard as a whole is written on the presumption that compiler writers will treat places where the Standard imposes no requirements as an invitation to use common sense, rather than as a call to throw common sense out the window. If on some hardware platform an attempted write to a const-qualified `volatile` might possibly have useful semantics, a compiler writer should not prevent a programmer from accessing them without a compelling reason beyond the fact that the Standard imposes no requirements. – supercat Feb 19 '17 at 01:07
0

This line:

int * a = &v;

is a constraint violation. The compiler must produce a diagnostic message, and may reject the program. If the compiler produces an executable anyway, then that executable has completely undefined behaviour (i.e. the C Standard no longer covers the program at all).

The constraints violated are that volatile nor const may not be implicitly converted away.

To comply with the C standard, the pointer must have its pointed-to type having the same or stronger qualifiers as the object being pointed to, e.g.:

int const volatile *a = &v;

after which you will find that the line *a = 4; causes a compilation error.


A possible attempt might be:

int *a = (int *)&v;

This line must compile, but then it causes undefined behaviour to read or write via *a. The undefined behaviour is specified by C11 6.7.3/6 (C99 and C89 had similar text):

If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • If both the original variable and the pointer are `volatile` qualified, a quality compiler that acknowledges the existence of hardware features it knows nothing about should assume that the programmer wants the behavior that will result from an attempt to store the indicated value to the indicated location. The Standard does not require that compiler writers acknowledge the existence of unknown hardware features, and relies upon compiler writers to exercise common sense in exposing such features to programmers. When using things like EEPROM, it is in fact useful... – supercat Feb 19 '17 at 01:17
  • ...to have storage which is qualified as `const volatile` but then have functions which perform the necessary gymnastics to write it (which will, in many cases, include a write of the desired value to the desired address). I would be rather peeved at a compiler which forced any gymnastics beyond casting a pointer to `uint8_t volatile*` or `uint32_t volatile*` [depending upon hardware] to force it to generate the necessary write operation at the appropriate point in the sequence. – supercat Feb 19 '17 at 01:20