From what I understand it is assembler code that creates delay - one processor clock long.
For C/C++ language it should be like ; or {} = null statement.
Now my question is how to implement this C/C++ code and prevent my compiler (WinAVR: AVR-GCC) to delete this command during optimization (-Os or -O2).
Or is it simply better to use the assembler function and save myself from a headache?
I know I can use for-loop
1 2
volatile uint8_t foo
for(foo=0; foo<2; ++foo){}
but for that I have to create a variable = wasting 1 byte of RAM; correct?
The purpose of volatile, as I understand it, is to prevent the compiler from making assumptions about the current state of the variable, as in
1 2 3 4
volatileint i;
f(&i);
i = 0;
while (!i);
Without the volatile, that while might be changed to an infinite loop.
In JLBorges's example, no other code can possibly modify or check the value of i. I don't see any reason not to remove that code, beyond lack of cleverness.
See that's not how I understand it. My understanding was that writes take effect so that you can perform hardware register accesses.
1 2 3 4
volatileint* somereg = (int*)(0x12345678); // address of some reg
*somereg = 5; // <- this write will not be optimized away
*somereg = 10;
EDIT:
Note that volatile will have the effect you describe as well -- since the read inside the while loop will always occur, since it cannot be optimized away.
I agree, that write will not be optimized away. However, writes to the dereference of a volatile int * are not the same as writes to a volatile int whose address is never taken. Again, I don't see why it should not be possible to eliminate that for.
I'm not sure I follow your understanding of volatile.
The compiler can't eliminate the for because the counter is volatile, which means all reads/writes have to occur in the given sequence and cannot be optimized out. That is the entire purpose of the volatile keyword.
There shouldn't be any difference between writing to a volatile var via pointer or directly -- both have the same end result. If your understanding were correct, and the two were treated differently, a very simple (but ridiculous) workaround would be this:
volatile object - an object whose type is volatile-qualified, or a subobject of a volatile object, or a mutable subobject of a const-volatile object. Every access (read or write operation, member function call, etc.) on the volatile object is treated as a visible side-effect for the purposes of optimization (that is, within a single thread of execution, volatile accesses cannot be reordered or optimized out.
> I don't see any reason not to remove that code, beyond lack of cleverness.
I don't see any reason to be deliberately non-conforming, beyond gross stupidity.
The least requirements on a conforming implementation are:
— Access to volatile objects are evaluated strictly according to the rules of the abstract machine.
— At program termination, all data written into files shall be identical to one of the possible results that execution of the program according to the abstract semantics would have produced.
— The input and output dynamics of interactive devices shall take place in such a fashion that prompting output is actually delivered before a program waits for input. What constitutes an interactive device is implementation-defined.
These collectively are referred to as the observable behavior of the program.
-IS
writes to the dereference of a volatile int * are not the same as writes to a volatile int whose address is never taken
1 2 3 4
volatile uint32_t status = 0xDF3377FDu;
//Other process seraches for this specific pattern somewhere
//where stack of this process would be located and then
//uses this variable to commnicate with this process
For this to work, reads and writes should not be optimised and compiler cannot possibly know if someone other will write in corresponding memory, so it cannot make guesses.