user30336: I know there are already many questions why volatile is used when it comes to interrupts.
But explanations like this doesn't help to picture what really happens:

Specifically, it directs the compiler to load the variable from RAM
  and not from a storage register, which is a temporary memory location
  where program variables are stored and manipulated. Under certain
  conditions, the value for a variable stored in registers can be
  inaccurate.

Above is from the official Arduino website:
And below is the basic Atmega328 architecture:

Is it possible to explain the use/advantage of volatile by comparing it to the usual declaration way considering the above architecture?
I mean such way: If volatile int x is used, the CPU fetches this from this  by this way ect. And if instead int x is used the instruction flow works like this so forth and so on.
Unfortunately I have difficulty to understand from plain two sentence explanations. 
As you see my question is about after the compilation what do we observe as a benefit inside the hardware during the instruction flow.

user10794: Let me explain it like this. Modern compilers optimize. They do this to make things run faster. People would complain if they didn't, or switch to another compile that does optimize.
Here's an analogy. Let's say you are wondering how many cats your brother has. You call him up on the phone, and he says "two".
A week later your friend asks how many cats your brother has. You say "I'll call him up and ask him.". 
Your friend says "Didn't you do that last week? How many did he have then?"
You reply, "Yeah, that's right. He must still have two cats, right? I've just saved the expense of a phone call!"
Not making the phone call is an optimization - you save time and money by not doing it. However what if your brother now has another cat? Or he gave one away? The information about the number of cats is out of date.
If your brother is a cat dealer, or frequently changes his cat configuration you might say "the number of cats my brother has is volatile - I'll have to call him up again to make sure of the number."
So, if something happens behind your back (like in your brother's house - or in a computer program in an ISR) then you need to check again each time. However if you are sure that things haven't changed (eg. in your house you would know if you got a new cat) then you can optimize by not checking each time.
I agree with Gerben's comment on this page. This is nothing to do with the compiler architecture - any more than the number of cats you have depends on the way the house is built.

user7508: Short answer: no, volatile cannot be explained in terms of the
figure you show in your question.
Longer answer: there is no direct link between the meaning of volatile
and the architecture depicted in the figure. If you insist in linking
them together, it is possible to find a very weak and indirect link
as follows:

Volatile is all about preventing the compiler from doing some
optimizations when translating your program to assembly. Looking at the
generated assembly can help understanding the effect of volatile.
When learning the assembly language, the figure you show is helpful
in understanding the assembly instructions themselves.

As you see, the link is indirect, mostly because we are talking about
different abstraction levels. Also, the link is weak because the figure
describes specifically the AVR architecture, whereas volatile applies
to any architectures for which there is a C compiler.
To illustrate the first point above, here is an example program which
shows the effect of volatile:
volatile bool volatile_flag;
bool plain_flag;

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    Serial.print("Waiting for volatile flag... ");
    while (!volatile_flag) ; /* wait */
    Serial.println("done.");

    Serial.print("Waiting for plain flag... ");
    while (!plain_flag) ; /* wait */
    Serial.println("done.");
}

As such, the program is not very interesting, it will just hang on the
first loop. But you can imagine there being some ISR that can set the
flags when some external event happens. Then the wait loops would start
to make sense, as they wait for the external event.
Here is the disassembly of the loop() function:
    Serial.print("Waiting for volatile flag... ");
  ce:   60 e0           ldi r22, 0x00   ; 0
  d0:   71 e0           ldi r23, 0x01   ; 1
  d2:   82 e5           ldi r24, 0x52   ; 82
  d4:   91 e0           ldi r25, 0x01   ; 1
  d6:   0e 94 b3 02     call    0x566   ; 0x566 <Print::print(char const*)>
    while (!volatile_flag) ; /* wait */
  da:   80 91 51 01     lds r24, 0x0151
  de:   88 23           and r24, r24
  e0:   e1 f3           breq    .-8         ; 0xda <loop+0xc>
    Serial.println("done.");
  e2:   6e e1           ldi r22, 0x1E   ; 30
  e4:   71 e0           ldi r23, 0x01   ; 1
  e6:   82 e5           ldi r24, 0x52   ; 82
  e8:   91 e0           ldi r25, 0x01   ; 1
  ea:   0e 94 d0 02     call    0x5a0   ; 0x5a0 <Print::println(char const*)>
    Serial.print("Waiting for plain flag... ");
  ee:   64 e2           ldi r22, 0x24   ; 36
  f0:   71 e0           ldi r23, 0x01   ; 1
  f2:   82 e5           ldi r24, 0x52   ; 82
  f4:   91 e0           ldi r25, 0x01   ; 1
  f6:   0e 94 b3 02     call    0x566   ; 0x566 <Print::print(char const*)>
    while (!plain_flag) ; /* wait */
  fa:   80 91 50 01     lds r24, 0x0150
  fe:   81 11           cpse    r24, r1
 100:   01 c0           rjmp    .+2         ; 0x104 <loop+0x36>
 102:   ff cf           rjmp    .-2         ; 0x102 <loop+0x34>
    Serial.println("done.");
 104:   6e e1           ldi r22, 0x1E   ; 30
 106:   71 e0           ldi r23, 0x01   ; 1
 108:   82 e5           ldi r24, 0x52   ; 82
 10a:   91 e0           ldi r25, 0x01   ; 1
 10c:   0c 94 d0 02     jmp 0x5a0   ; 0x5a0 <Print::println(char const*)>

The important thing to notice is how the compiler implemented the
waiting loops. The first one is essentially
0:  lds r24, volatile_flag  ; load the flag from RAM
    tst r24                 ; test it
    breq 0b                 ; if zero, loop back

whereas the second loop is:
    lds r24, plain_flag     ; load the flag from RAM
    cpse r24, r1            ; if zero, skip the following jump
    rjmp 1f                 ; jump over the next loop
0:  rjmp 0b                 ; infinite loop
1:

You may appreciate the first loop has been translated to assembly in a
very literal way, whereas in the second loop the compiler optimized away
all but the first read of the variable. That could be translated back to
C as
if (!plain_flag) {
    for (;;) ;  // hang in an infinite loop
}

The compiler assumed the flag cannot be changed by some external event,
so there is no point in reading it repeatedly. The volatile keyword
prevents the compiler from making such assumption.
And how is all this related to your figure you may ask? Well, if you
happened to not understand the assembly code above, you could check the
AVR Instruction Set Manual to see what each instruction does,
and that's when the figure becomes helpful.

30336: <p>I know there are already many questions why <strong>volatile</strong> is used when it comes to interrupts.</p>

<p>But explanations like this doesn't help to picture what really happens:</p>

<blockquote>
  <p>Specifically, it directs the compiler to load the variable from RAM
  and not from a storage register, which is a temporary memory location
  where program variables are stored and manipulated. Under certain
  conditions, the value for a variable stored in registers can be
  inaccurate.</p>
</blockquote>

<p>Above is from the official Arduino <a href="https://www.arduino.cc/en/Reference/Volatile" rel="nofollow noreferrer">website</a>:</p>

<p>And below is the basic Atmega328 architecture:</p>

<p><a href="https://i.stack.imgur.com/svHbz.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/svHbz.png" alt="enter image description here"></a></p>

<p><em>Is it possible to explain the use/advantage of volatile by comparing it to the usual declaration way considering the above architecture?</em></p>

<p>I mean such way: If <strong>volatile int x</strong> is used, the CPU fetches this from this  by this way ect. And if instead <strong>int x</strong> is used the instruction flow works like this so forth and so on.</p>

<p>Unfortunately I have difficulty to understand from plain two sentence explanations. </p>

<p>As you see my question is about after the compilation what do we observe as a benefit inside the hardware during the instruction flow.</p>
 10794: <p>Let me explain it like this. Modern compilers <strong>optimize</strong>. They do this to make things run faster. People would complain if they didn't, or switch to another compile that does optimize.</p>

<p>Here's an analogy. Let's say you are wondering how many cats your brother has. You call him up on the phone, and he says "two".</p>

<p>A week later your friend asks how many cats your brother has. You say "I'll call him up and ask him.". </p>

<p>Your friend says "Didn't you do that last week? How many did he have then?"</p>

<p>You reply, "Yeah, that's right. He must still have two cats, right? I've just saved the expense of a phone call!"</p>

<p>Not making the phone call is an <strong>optimization</strong> - you save time and money by not doing it. However what if your brother now has another cat? Or he gave one away? The information about the number of cats is out of date.</p>

<p>If your brother is a cat dealer, or frequently changes his cat configuration you might say "the number of cats my brother has is <strong>volatile</strong> - I'll have to call him up again to make sure of the number."</p>

<p>So, if something happens <em>behind your back</em> (like in your brother's house - or in a computer program in an ISR) then you need to check again each time. However if you are sure that things haven't changed (eg. in your house you would know if you got a new cat) then you can optimize by not checking each time.</p>

<p>I agree with Gerben's comment on this page. This is nothing to do with the compiler architecture - any more than the number of cats you have depends on the way the house is built.</p>
 7508: <p>Short answer: <strong>no</strong>, <code>volatile</code> cannot be explained in terms of the
figure you show in your question.</p>

<p>Longer answer: there is no direct link between the meaning of <code>volatile</code>
and the architecture depicted in the figure. If you insist in linking
them together, it is possible to find a very <em>weak</em> and <em>indirect</em> link
as follows:</p>

<ol>
<li><p>Volatile is all about preventing the compiler from doing some
optimizations when translating your program to assembly. Looking at the
generated assembly <strong>can</strong> help understanding the effect of <code>volatile</code>.</p></li>
<li><p>When learning the assembly language, the figure you show is helpful
in understanding the assembly instructions themselves.</p></li>
</ol>

<p>As you see, the link is indirect, mostly because we are talking about
different abstraction levels. Also, the link is weak because the figure
describes specifically the AVR architecture, whereas <code>volatile</code> applies
to any architectures for which there is a C compiler.</p>

<p>To illustrate the first point above, here is an example program which
shows the effect of <code>volatile</code>:</p>

<pre class="lang-c++ prettyprint-override"><code>volatile bool volatile_flag;
bool plain_flag;

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    Serial.print("Waiting for volatile flag... ");
    while (!volatile_flag) ; /* wait */
    Serial.println("done.");

    Serial.print("Waiting for plain flag... ");
    while (!plain_flag) ; /* wait */
    Serial.println("done.");
}
</code></pre>

<p>As such, the program is not very interesting, it will just hang on the
first loop. But you can imagine there being some ISR that can set the
flags when some external event happens. Then the wait loops would start
to make sense, as they wait for the external event.</p>

<p>Here is the disassembly of the <code>loop()</code> function:</p>

<pre><code>    Serial.print("Waiting for volatile flag... ");
  ce:   60 e0           ldi r22, 0x00   ; 0
  d0:   71 e0           ldi r23, 0x01   ; 1
  d2:   82 e5           ldi r24, 0x52   ; 82
  d4:   91 e0           ldi r25, 0x01   ; 1
  d6:   0e 94 b3 02     call    0x566   ; 0x566 &lt;Print::print(char const*)&gt;
    while (!volatile_flag) ; /* wait */
  da:   80 91 51 01     lds r24, 0x0151
  de:   88 23           and r24, r24
  e0:   e1 f3           breq    .-8         ; 0xda &lt;loop+0xc&gt;
    Serial.println("done.");
  e2:   6e e1           ldi r22, 0x1E   ; 30
  e4:   71 e0           ldi r23, 0x01   ; 1
  e6:   82 e5           ldi r24, 0x52   ; 82
  e8:   91 e0           ldi r25, 0x01   ; 1
  ea:   0e 94 d0 02     call    0x5a0   ; 0x5a0 &lt;Print::println(char const*)&gt;
    Serial.print("Waiting for plain flag... ");
  ee:   64 e2           ldi r22, 0x24   ; 36
  f0:   71 e0           ldi r23, 0x01   ; 1
  f2:   82 e5           ldi r24, 0x52   ; 82
  f4:   91 e0           ldi r25, 0x01   ; 1
  f6:   0e 94 b3 02     call    0x566   ; 0x566 &lt;Print::print(char const*)&gt;
    while (!plain_flag) ; /* wait */
  fa:   80 91 50 01     lds r24, 0x0150
  fe:   81 11           cpse    r24, r1
 100:   01 c0           rjmp    .+2         ; 0x104 &lt;loop+0x36&gt;
 102:   ff cf           rjmp    .-2         ; 0x102 &lt;loop+0x34&gt;
    Serial.println("done.");
 104:   6e e1           ldi r22, 0x1E   ; 30
 106:   71 e0           ldi r23, 0x01   ; 1
 108:   82 e5           ldi r24, 0x52   ; 82
 10a:   91 e0           ldi r25, 0x01   ; 1
 10c:   0c 94 d0 02     jmp 0x5a0   ; 0x5a0 &lt;Print::println(char const*)&gt;
</code></pre>

<p>The important thing to notice is how the compiler implemented the
waiting loops. The first one is essentially</p>

<pre><code>0:  lds r24, volatile_flag  ; load the flag from RAM
    tst r24                 ; test it
    breq 0b                 ; if zero, loop back
</code></pre>

<p>whereas the second loop is:</p>

<pre><code>    lds r24, plain_flag     ; load the flag from RAM
    cpse r24, r1            ; if zero, skip the following jump
    rjmp 1f                 ; jump over the next loop
0:  rjmp 0b                 ; infinite loop
1:
</code></pre>

<p>You may appreciate the first loop has been translated to assembly in a
very literal way, whereas in the second loop the compiler optimized away
all but the first read of the variable. That could be translated back to
C as</p>

<pre class="lang-c++ prettyprint-override"><code>if (!plain_flag) {
    for (;;) ;  // hang in an infinite loop
}
</code></pre>

<p>The compiler assumed the flag cannot be changed by some external event,
so there is no point in reading it repeatedly. The <code>volatile</code> keyword
prevents the compiler from making such assumption.</p>

<p>And how is all this related to your figure you may ask? Well, if you
happened to not understand the assembly code above, you could check the
<a href="http://www.atmel.com/images/Atmel-0856-AVR-Instruction-Set-Manual.pdf" rel="nofollow noreferrer">AVR Instruction Set Manual</a> to see what each instruction does,
and <strong>that's</strong> when the figure becomes helpful.</p>
