This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

"VOLATILE" IS VERY C0NFUSING

I AM NOT UNDERSTANDING THE SITUATION WHEN SHOULD I USE "VOLATILE" WITH VARIABLES ???

Parents
  • http://www.netrino.com/node/80

    Excellent article!

    But there is one additional case where volatile might be needed:

    void inaccurate_delay( unsinged int x ) // create a short, inaccurate delay
    {
       volatile unsinged int i;
    
       for( i=x; i>0; i++ )
       {
          // do nothing
       }
    }
    


    Without the volatile qualifier, the compiler would be entirely justified in optimising-out the entire for loop - since it does nothing!

    Of course, you should never use high-level languages for any sort of predictable timing - see: www.8052.com/.../read.phtml

    And you should never use any sort of loop for any long time delay.

Reply
  • http://www.netrino.com/node/80

    Excellent article!

    But there is one additional case where volatile might be needed:

    void inaccurate_delay( unsinged int x ) // create a short, inaccurate delay
    {
       volatile unsinged int i;
    
       for( i=x; i>0; i++ )
       {
          // do nothing
       }
    }
    


    Without the volatile qualifier, the compiler would be entirely justified in optimising-out the entire for loop - since it does nothing!

    Of course, you should never use high-level languages for any sort of predictable timing - see: www.8052.com/.../read.phtml

    And you should never use any sort of loop for any long time delay.

Children
  • Without the volatile qualifier, the compiler would be entirely justified in optimising-out the entire for loop - since it does nothing!

    Hmm, that's debatable. If I was the compiler, I would optimize the empty loop anyway, even with the loop variable being volatile. Having read the C standard quite a bit, I cannot see which part of it exactly implies that declaring the loop variable as volatile protects the loop from being eliminated.

  • Hmm... interesting point.

    But doesn't the i++ involve an implicit read of i, and making i volatile means that read cannot be optimised-out? Therefore the entire loop can't be optimised-out?

    Well, that's my initial thought off the top of my head - I'll have to go back to my 'C' spec to see if I can back it up...

  • But doesn't the i++ involve an implicit read of i, and making i volatile means that read cannot be optimised-out?

    Well, I mentioned the standard, but what I actually had in mind is the following. In the code you presented, since the variable i is local to the function, the only conceivable way for it to change in an 'unpredictable' way is when you use a pointer to it elsewhere. Since that didn't happen, nothing prevents the compiler from concluding that the code has no effect.

    There is a sentence in the standard which could support this view:

    What constitutes an access to an object that has volatile-qualified type is implementation-defined

    An implementation might say "If a volatile automatic variable is qualified to be placed in a CPU register by during compilation, the compiler is allowed to optimize away accesses to this variable." It makes sense and it doesn't seem to violate the standard.

  • I cannot see which part of it exactly implies that declaring the loop variable as volatile protects the loop from being eliminated.

    The part where it says that volatile makes the execution environment behave just like the language definition says the virtual machine will. So as the language has that for loop write values into the loop variable, the real machine must do that, too. It has to perform all reads and writes of that variable exactly as expressed in the source. At every sequence point, the value of every variable in the program has to be in exactly the state defined by the language and the source code. I.e. no short-cuts, not even for automatic variables.

  • The part where it says that volatile makes the execution environment behave just like the language definition says the virtual machine will.

    Actually, it doesn't say this. It says that that accesses to volatile objects will be made according to the rules of the abstract machine. And, according to the standard, 'What constitutes an access to an object that has volatile-qualified type is implementation-defined.'

    At every sequence point, the value of every variable in the program has to be in exactly the state defined by the language and the source code.

    Exactly. But that doesn't prevent the compiler from eliminating empty loops, despite the fact that the loop has a number sequence points, and variables modified between those points.
    Another thing: how can the values of those variables be observed? They can only be observed through the actions of that same program. The debugger doesn't count, the standard does not mention it.
    In Andy's example, it is clear that the volatile variable cannot affect anything, and the compiler can easily deduce this. So a minor clause in the 'implementation-defined behaviour' will allow the compiler to eliminate the loop, thus producing more efficient code.

  • If I wrote a compiler, I would be inclined to think that it would be ok to remove the loop, since writes to an auto variable can have no side effets - besides overflowing a too small stack, or producing non-productive bus accesses.

    But I don't think I have seen any compiler who will remove the loop if the variable is volatile.

  • Probably, as Mike suggests, the letter of the law would permit the compiler to optimise-out such loops.

    In practice, compiler writers - especially embedded compiler writers - probably realise that their customers do make use of such loops, and so they choose not to.

  • In practice, compiler writers - especially embedded compiler writers - probably realise that their customers do make use of such loops, and so they choose not to.

    Actually, I prefer it this way too: better safe than sorry. It's probably possible to take the spec to such an extreme that the resulting compiler wouldn't be useful for much of anything.
    It reminded me of this thread on the Linux kernel mailing list:
    kerneltrap.org/.../359162

  • Another thing: how can the values of those variables be observed? They can only be observed through the actions of that same program.

    This argument, essentially a subset of the "as-if" rule, holds for normal variables, but not for volatile-qualified ones. Forbidding application of the as-if rule is exactly what volatile is about. Following your line of reasoning, volatile might as well imply static duration, since it doesn't have any effect on automatic variables.

    Also note C99 5.1.2.3: writes to volatile objects are side-effects, and as such they have to be completed before the next sequence point. I rather much doubt that the seeming loop-hole 6.7.3p6 about implementation-definedness of "access to a volatile object" should be understood to cover writing a value to it. Particularly as it stands after a clause of the pattern "except ... as mentioned previously"

  • In practice, compiler writers - especially embedded compiler writers - probably realise that their customers do make use of such loops, and so they choose not to.

    Optimising away writes to a volatile variable would always be at least a straight violation of the programmer's expressed will, even if the standard can be bent into seemingly allowing it.

    Even setting aside volatile, the GCC guys have a particularly clever idea about optimizing away entire loops: if a non-empty loop body was optimized away, the loop itself is removed, too. If the loop body was empty in the first place, they leave the entire loop alone, under the assumption that nobody would write an empty loop lest they really mean it.

  • It seems to depend a lot on gcc version. Most probably, only versions before 4.x keep empty loops.

    Test with empty loop and -O3:

    gcc 2.95.4 leaves loop.
    gcc 3.0.4 leaves loop.
    gcc 3.3.1 leaves loop.
    gcc 3.3.5 leaves loop.
    gcc 3.3.6 leaves loop.
    gcc 4.1.2 strips loop.

  • Is it required in the following case to declare PortPin as volatile :

    sbit PortPin = P3^7 ;

    /////// check k/b ststus

    If (PortPin = 0 )
    { ///// some kb routine

    do

    while (PortPin ==0)
    }

  • "Is it required in the following case to declare PortPin as volatile"

    I seem to recall some time ago (years ago?) Keil saying that SFRs and their bit objects are implicitly volatile. I could not find a reference to that in an extremely short time searching. I'll try again when I have time.

  • Yes, I seem to recall that, too!

    I also seem to recall not being able to find it (clearly) documented anywhere...