Forum: Compiler & IDEs Attribute und pointer-type


von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Hallo zusammen!

Ich habe da ein kleines Verständnisproblem mit den GCC-Attributen für 
Typen.
Ich möchte eine Callbackfunktion auf einem AT91SAM7S64 ins RAM 
verlagern, wobei ich folgendes Makro verwende:
1
#define __ramfunc __attribute__ ((long_call, section (".fastrun")))

Das "Event" wird in die Timeoutqueue eines kleinen, aber sehr 
nützlichen, Tools von Jörg Wunsch (das Bier hast Du Dir wirklich 
verdient ;) wie folgt eingelassen:
1
  /* Enable displayclock: */
2
  timeout(1000, showclock, (union timeoutarg) NULL);

Die Implementation der Callbackfunktion sieht so aus:
1
/* Callback function for the clock: */
2
__ramfunc void
3
showclock(union timeoutarg targ)
4
{
5
        time_t timer;
6
        struct tm *ltime;
7
8
        /* retrigger displayclock: */
9
        timeout(1000, showclock, (union timeoutarg)NULL);
10
11
        timer = lt_copy + (clock()/1000);
12
        ltime = localtime(&timer);
13
14
        /* fancy clock - this should get a prompt one day ;-) */
15
        rprintf(" [%02d:%02d:%02d] %u:/>\r", ltime->tm_hour, ltime->tm_min, ltime->tm_sec, dmxStartAddress);
16
}

Die Warnung des Compilers dann so:
1
main.c:325: warning: passing argument 2 of 'timeout' from incompatible pointer type

Meine Fragen:

  1. Wo gehört "__attribute__" hin?
     - vor den Prototypen
     - hinter den Prototypen
     - vor den Funktionsrumpf
     - hinter die schliessende Klammer der Argumentliste
     - vor/hinter Prototyp und Funktionsrumpf
  2. Warum verändert es den Pointertypen?
  3. Wäre ein Cast hier richtig?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Patrick Dohmen wrote:

>   1. Wo gehört "__attribute__" hin?
>      - vor den Prototypen
>      - hinter den Prototypen
>      - vor den Funktionsrumpf
>      - hinter die schliessende Klammer der Argumentliste
>      - vor/hinter Prototyp und Funktionsrumpf

Hmm, ich mache es immer so:
1
rettype myfunc(arglist) __attribute__((...));
2
rettype
3
myfunc(arglist)
4
{
5
  /* implementation */
6
}
Ich bin mich nicht sicher, welche Wege es noch gäbe.

>   2. Warum verändert es den Pointertypen?

"Das ist eben so." :-)

Naja, auch derjenige, der die Callback-Funktion ruft, muss ja
u. U. darüber etwas wissen.  Wenn ich das richtig sehe (kenne mich mit
ARM nicht aus), verlässt du ja damit den normalen Weg, wie der
Compiler einen indirekten Funktionsaufruf zusammenbasteln würde.
Damit muss er natürlich auch innerhalb des Timeout-Handlers wissen,
dass er anderen Code generieren soll.

>   3. Wäre ein Cast hier richtig?

Erst einmal nicht.  Richtig wäre es, die Attribute auch in der
Timerqueue sauber mitzuführen.  Ob der Cast tolerierbar wäre, hängt
letztlich davon ab, ob meine bei 2. genannten Ausführungen tatsächlich
Auswirkungen auf den generierten Code haben oder nicht.

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Hm, Deine Vorgehensweise ergibt folgenden Fehler:
1
void showclock(union timeoutarg targ) __ramfunc;
2
3
[..]
4
5
void
6
showclock(union timeoutarg targ)
7
{
8
9
[..]
10
11
}
1
main.c:320: error: conflicting types for 'showclock'
2
main.c:22: error: previous declaration of 'showclock' was here

Irgendwie blick ich das nicht...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Seltensam.  Genau auf diese Weise werden aber beispielsweise die
ISRs bei avr-libc deklariert.

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Jörg Wunsch wrote:

>>   3. Wäre ein Cast hier richtig?
>
> Erst einmal nicht.  Richtig wäre es, die Attribute auch in der
> Timerqueue sauber mitzuführen.  Ob der Cast tolerierbar wäre, hängt
> letztlich davon ab, ob meine bei 2. genannten Ausführungen tatsächlich
> Auswirkungen auf den generierten Code haben oder nicht.

Das heist also, ich müsste den Funktionsprototypen aus "timer.h" 
umbauen...
1
/* the action function itself */
2
typedef void (*timeout_t)(union timeoutarg);

...wird zu:
1
/* the action function itself */
2
typedef void (*timeout_t)(union timeoutarg) __ramfunc;

Ich werd's mal ausprobieren!

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Heh, denkste! :-)
1
timer.h:24: error: section attribute not allowed for 'timeout_t'

Naja, ich such mich mal schlau...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Patrick Dohmen wrote:

> Heh, denkste! :-)

>
1
> timer.h:24: error: section attribute not allowed for 'timeout_t'
2
>

Naja, die section ist nicht so wichtig (die wird ja nur für den Linker
gebraucht, damit er den Code der Funktion an die passende Stelle
packen kann), aber was ist mit dem long_call?

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Na hups!
Ich wollte nicht unhöflich sein, ich hab den Beitrag irgendwie aus den 
Augen verloren.

Das mit dem 'long_call' als einziges Attribut werde ich nachher mal 
ausprobieren, danke für den Hinweis!

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

So funktioniert es:

1. Funktionspointer
1
/* the action function itself */
2
typedef __attribute__ ((long_call)) void (*timeout_t)(union timeoutarg);

2. Funktionsprototyp für callback Implementation
1
/* callback functions */
2
__ramfunc void showclock(union timeoutarg targ);

3. Funktionsdeklaration
1
__ramfunc void
2
showclock(union timeoutarg targ)
3
{
4
    [...]
5
}

Stelle ich die Attribute ans Ende, wird immer wieder 'redeclaration' 
bemängelt.
Seltsame Sache...

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.