Forum: Compiler & IDEs Problem mit atomic Funktionen


von Peter D. (peda)


Lesenswert?

Ich hab mal versucht, die neuen atomic Funktionen des WINAVR zu 
benutzen.
Der Code wird auch korrekt compiliert, aber es gibt leider eine 
Fehlermeldung:

ATOMIC.C: In function 'test':
ATOMIC.C:10: warning: control reaches end of non-void function

Hier der Code:
1
#include <util\atomic.h>
2
3
volatile int var;
4
5
int test( void )
6
{
7
  ATOMIC_BLOCK(ATOMIC_FORCEON){
8
    return var;
9
  }
10
}


Peter

von Nico (Gast)


Lesenswert?

Nur mal als Anmerkung:
1
#include <util\atomic.h>

Das nutzen eines Backslash hier ist wirklich eine üble Unsitte, die sich 
unter Windows-Programmierern leider eingebürgert hat. Der Backslash 
dient in C (und auch im PreProcessor) eigentlich als Escape.

von Peter (Gast)


Lesenswert?

ich habe zwar keine ahnung was das atomic auf einem Atmel macht aber die 
Warnung kommt weil die Funktion ein ende ohne return hat.

int test( void )
{
  ATOMIC_BLOCK(ATOMIC_FORCEON){
    return var;
  }
  return 0;
}


jetzt sollte die Warnung weg sein.

von Peter D. (peda)


Lesenswert?

Peter wrote:
> ich habe zwar keine ahnung was das atomic auf einem Atmel macht

Du hast also bisher noch nie Interrupts benutzt?

Atomic macht die notwendige CLI/SEI-Klammerung für den Zugriff auf 
Interruptvariablen im Main.


> jetzt sollte die Warnung weg sein.

Sieht zwar etwas irritierend aus, aber die Warnung ist weg.
Das "return 0;" wird auch wieder wegoptimiert.


Peter

von Oliver (Gast)


Lesenswert?

>aber die Warnung kommt weil die Funktion ein ende ohne return hat.

Genaugenommen kommt die Warnung wohl, weil der Compiler nicht versteht, 
daß return(var) immer erreicht wird.

Oliver

von Peter (Gast)


Lesenswert?

> > ich habe zwar keine ahnung was das atomic auf einem Atmel macht
> Du hast also bisher noch nie Interrupts benutzt?
Doch habe ich, aber ich ziehe es bisher vor, selber zu entscheiden wenn 
ich die Interrupts abschalte und wann nicht.

von Peter D. (peda)


Lesenswert?

Peter wrote:
> Doch habe ich, aber ich ziehe es bisher vor, selber zu entscheiden wenn
> ich die Interrupts abschalte und wann nicht.

Eigentlich wollte ich mit den atomic Funktionen die Lesbarkeit 
verbessern.

Aber das "return 0;" ist kontraproduktiv, weil es suggeriert, es könnte 
0 statt val zurückgegeben werden.


Peter

von Peter (Gast)


Lesenswert?

dann mach es mit

int test( void )
{
  int tmp;
  ATOMIC_BLOCK(ATOMIC_FORCEON){
    tmp=var;
  }
  return tmp;
}

von Peter (Gast)


Lesenswert?

oh da kommt bestimmt die Warnung das eine nicht initalisierte Variable 
genutzt wird. Also 2. Versuch
1
int test( void )
2
{
3
  int tmp = 0;
4
  ATOMIC_BLOCK(ATOMIC_FORCEON){
5
    tmp=var;
6
  }
7
  return tmp;
8
}

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger schrob:

>
1
> int test( void )
2
> {
3
>   ATOMIC_BLOCK(ATOMIC_FORCEON){
4
>     return var;
5
>   }
6
> }
7
>

Ist das denn überhaupt sinnvoll?

Wenn zB der Block vor dem return ein CLI und danach ein SEI einfügt, 
dann wird das SEI nie mehr ausgeführt (bzw, Restaurierung des I-Flags).

BTW dürften das keine Funktionen sein sondern Makros, also einfach mal 
anschauen was der Präprozessor draus macht bzw. ein Blick in die Doku 
wagen.

Das Atomic-Zeug ist wohl für blöcke gedacht, die die schliessende } auch 
erreichen und nicht per goto oder return oder sonstwas den atomic block 
verlassen.

von Stefan E. (sternst)


Lesenswert?

Johann L. wrote:

> Wenn zB der Block vor dem return ein CLI und danach ein SEI einfügt,
> dann wird das SEI nie mehr ausgeführt (bzw, Restaurierung des I-Flags).
>
> BTW dürften das keine Funktionen sein sondern Makros, also einfach mal
> anschauen was der Präprozessor draus macht bzw. ein Blick in die Doku
> wagen.
>
> Das Atomic-Zeug ist wohl für blöcke gedacht, die die schliessende } auch
> erreichen und nicht per goto oder return oder sonstwas den atomic block
> verlassen.

Nicht nach der Dokumentation:
These macros operate via automatic manipulation of the Global Interrupt 
Status (I) bit of the SREG register. Exit paths from both block types 
are all managed automatically without the need for special 
considerations, i. e. the interrupt status will be restored to the same 
value it has been when entering the respective block.

Man beachte hier das
> Exit paths from both block types are all managed automatically

Wie das genau erreicht wird, habe ich mir aber noch nicht angeschaut.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan Ernst schrob:
> Nicht nach der Dokumentation:
> These macros operate via automatic manipulation of the Global Interrupt
> Status (I) bit of the SREG register. Exit paths from both block types
> are all managed automatically without the need for special
> considerations, i. e. the interrupt status will be restored to the same
> value it has been when entering the respective block.
>
> Man beachte hier das
>> Exit paths from both block types are all managed automatically
>
> Wie das genau erreicht wird, habe ich mir aber noch nicht angeschaut.

Stimmt, wird recht geschickt über __attribute__((_cleanup_)) gemacht, 
sehr interessant das. Kannte ich noch garnicht.
1
static __inline__ uint8_t __iSeiRetVal(void)
2
{
3
    __asm__ __volatile__ ("sei" ::);
4
    return 1;
5
}
6
7
static __inline__ uint8_t __iCliRetVal(void)
8
{
9
    __asm__ __volatile__ ("cli" ::);
10
    return 1;
11
}
12
13
static __inline__ void __iSeiParam(const uint8_t *__s)
14
{
15
    __asm__ __volatile__ ("sei" ::);
16
    __asm__ volatile ("" ::: "memory");
17
    (void)__s;
18
}
19
20
static __inline__ void __iCliParam(const uint8_t *__s)
21
{
22
    __asm__ __volatile__ ("cli" ::);
23
    __asm__ volatile ("" ::: "memory");
24
    (void)__s;
25
}
26
27
static __inline__ void __iRestore(const uint8_t *__s)
28
{
29
    (*(volatile uint8_t *)((0x3F) + 0x20)) = *__s;
30
    __asm__ volatile ("" ::: "memory");
31
}
32
# 2 "main.c" 2
33
34
volatile int var;
35
36
int test( void )
37
{
38
  for ( uint8_t sreg_save __attribute__((__cleanup__(__iSeiParam))) = 0, __ToDo = __iCliRetVal(); __ToDo ; __ToDo = 0 ){
39
    return var;
40
  }
41
}

Jedenfalls wird korrekter Code erzeugt, und IMHO kommt die Warnung hier 
fälschlicher Weise, wenn es auch nichst einfach sein dürfte das im 
Compiler zu fixen; dazu müsste die Warnung in einem späteres Pass kommen 
als sie es jetzt tut.

von Rolf Magnus (Gast)


Lesenswert?

> Stimmt, wird recht geschickt über __attribute__((cleanup)) gemacht,
> sehr interessant das. Kannte ich noch garnicht.

Ist an sich das RAII-Prinzip, wie es in C++ gerne eingesetzt wird. In C 
(mit gcc) muß man sich halt mit dem cleanup-Attribut helfen, weil es da 
keine Destruktoren gibt.


> int test( void )
> {
>   for ( uint8_t sreg_save __attribute__((__cleanup__(__iSeiParam))) = 0, > 
__ToDo = __iCliRetVal(); __ToDo ; __ToDo = 0 ){
>     return var;
>   }
> }
>
> Jedenfalls wird korrekter Code erzeugt, und IMHO kommt die Warnung
>  hierfälschlicher Weise,

Ich schätze, er erkennt nicht, daß die for-Schleife immer genau einmal 
ausgeführt wird.

von Matthias L. (Gast)


Lesenswert?

Woher bekommt man denn die atomic.h Datei?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?


Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.