volatile cast: GCC Bug oder gültige Optimierung

Gast #3298316
Lesenswert?

Ich habe hier ein kleines Problem, für welches ich zwar einen Workaround 
habe, aber nicht sicher bin, ob das ein GCC Bug ist.

Und zwar sollen im Code Zeichen asynchron über den UART gelesen werden 
bis ein gültiges Längenbyte (!=0) kommt. Über den Code Stil kann man 
streiten, aber er sollte so funktionieren, und tat das auch bis wir Link 
Time Optimization verwendeten und dabei ein Call durch Inlinen ersetzt 
wurde.

Ich hab als Beispiel was gebastelt, das diese Auffälligkeiten zeigt, 
dabei sind 3 Beispiele zu sehen, im ersten wird bei der if Überprüfung 
in der Schleife der zweite Teil weggelassen, obwohl auf (volatile ...) 
gecastet. Darf der Compiler das, obwohl ich ihm sage die Variable kann 
sich (durch die UART ISR) ändern?
Bei den beiden anderen Varianten wird alles wie gewünscht ausgeführt. Am 
besten man kompiliert das immer nur mit einer Schleife, dann sieht man 
im Listing was ich meine. Optimierung ist -Os mit GCC 4.7.2 von 
Launchpad

Plattform ist ein STM32
1
#include <stdint.h>
2
 
3
static char m_cRecBuffer[23];
4

5
void __attribute__((noinline)) uart_read_async(uint8_t* pa_pcBuffer, int pa_nLen)
6
{
7
   volatile uint8_t * pUartBusy = (volatile uint8_t*)0x42; 
8
   *pUartBusy = 1;
9
}
10
 
11
 uint8_t __attribute__((noinline)) uart_is_busy()
12
 {
13
    volatile uint8_t * pUartBusy = (volatile uint8_t*)0x42; 
14
   return *pUartBusy; 
15
 }
16
 
17
 void _exit(int pa_Exit)
18
 {
19
 }
20
 
21
int main(void)
22
{
23

24
   m_cRecBuffer[0] = 0;
25
   uart_read_async(&m_cRecBuffer[0], 1);
26
   
27
   // some pointer to uart driver status, changed in uart ISR
28
   volatile uint8_t * p_UartBusy = (volatile uint8_t*)0x42; 
29
   
30
   // not working
31
   /*
32
   * second condition in if is ignored (0 == (volatile uint8_t)m_cRecBuffer[0])
33
   */
34
   while ((0 == (volatile uint8_t)m_cRecBuffer[0])) {
35
    if (*p_UartBusy != 0 && (0 == (volatile uint8_t)m_cRecBuffer[0])) {
36
      uart_read_async(&m_cRecBuffer[0], 1);
37
    }
38
   }
39
   
40
   // working
41
   while ((0 == (volatile uint8_t)m_cRecBuffer[0])) {
42
    if (uart_is_busy() != 0 && (0 == (volatile uint8_t)m_cRecBuffer[0])) {
43
      uart_read_async(&m_cRecBuffer[0], 1);
44
    }
45
   }
46
   
47
   // working
48
   volatile uint8_t * pcLen = (volatile uint8_t*) &m_cRecBuffer[0];
49
   while (0 == *pcLen) {
50
    if (*p_UartBusy != 0 && 0 == *pcLen) {
51
      uart_read_async(&m_cRecBuffer[0], 1);
52
    }
53
   }
54
}
Gast #3298342
Lesenswert?

Das der
>> (0 == (volatile uint8_t)m_cRecBuffer[0])
Teil wegoptimiert wird, könnte vielleicht daran liegen, dass du
m_cRecBuffer nicht als volatile deklariert ist. Das könntest mal 
ausprobieren.
Aber ich weiß auch nich, was ein volatile cast letztlich für 
Auswirkungen hat.
#3298370
Lesenswert?

Wenn man auf eine Variable, die nicht als "volatile" deklariert ist, 
erst einmal zugegriffen hat, dann ist es ziemlich egal, ob man den so 
erhaltenen Wert nachträglich zu "volatile" castet. Das ist so, als ob 
man den Stall zusperrt, nachdem das Pferd schon ausgebüxt ist.
Gast #3298381
Lesenswert?

Peter Dannegger schrieb:
> Also beim AVR-GCC läßt sich volatile nicht direkt casten.
Genau das ist das Problem. Du liest die *nicht*-volatile Variable 
m_recBuffer aus (kann also wegoptimiert werden) und castest das 
Ergebnis nach "volatile uint8_t".
In C wäre es so richtig:
1
while (0 == ((volatile uint8_t*)m_cRecBuffer)[0]) {
In C++:
1
while (0 == const_cast<volatile uint8_t*>(&m_cRecBuffer)[0]) {
(const_cast ist auch für volatile zuständig...)
Natürlich wäre es geschickter, m_cRecBuffer gleich komplett als 
"volatile" zu definieren.

Peter Dannegger schrieb:
> #define IVAR(x)         (*(volatile typeof(x)*)&(x))
Und für die 2 anderen C++-Programmierer hier um Forum:
1
template <typename T>
2
inline volatile T& IVAR (T& var) {
3
  return const_cast<volatile T&>(var);
4
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren