mikrocontroller.net

Forum: PC-Programmierung attribute noreturn


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Jens (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich sehe gerade bei einer static void Function in C das attribute 
"noreturn".
static void function(uint8_t x, uint8_t y) __attribute__((noreturn));

aber wofür das attribute? void gibt doch eh nichts zurück?

von Kaj (Gast)


Bewertung
1 lesenswert
nicht lesenswert
noreturn hat nichts mit dem Rueckgabewert zu tun, sondern sagt dem 
Compiler, das die Funktion nie verlassen wird. Dadurch kann der Compiler 
anders optimieren.

https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
 For example, you can use attributes to specify that a 
function never returns (noreturn),

von Kaj (Gast)


Bewertung
0 lesenswert
nicht lesenswert
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
noreturn

    A few standard library functions, such as abort and exit, cannot return. GCC knows this automatically. Some programs define their own functions that never return. You can declare them noreturn to tell the compiler this fact. For example,

    void fatal () __attribute__ ((noreturn));

    void
    fatal (/* … */)
    {
      /* … */ /* Print error message. */ /* … */
      exit (1);
    }

    The noreturn keyword tells the compiler to assume that fatal cannot return. It can then optimize without regard to what would happen if fatal ever did return. This makes slightly better code. More importantly, it helps avoid spurious warnings of uninitialized variables.

    The noreturn keyword does not affect the exceptional path when that applies: a noreturn-marked function may still return to the caller by throwing an exception or calling longjmp.

    In order to preserve backtraces, GCC will never turn calls to noreturn functions into tail calls.

    Do not assume that registers saved by the calling function are restored before calling the noreturn function.

    It does not make sense for a noreturn function to have a return type other than void.


von Walter T. (nicolas)


Bewertung
0 lesenswert
nicht lesenswert
Denn Sinn dahinter habe ich allerdings nie verstanden (außer bei 
main()). Wenn die Funktion niemals beendet wird - warum sollte ich sie 
beschleunigen wollen?

von Sven B. (scummos)


Bewertung
1 lesenswert
nicht lesenswert
Walter T. schrieb:
> Denn Sinn dahinter habe ich allerdings nie verstanden (außer bei
> main()). Wenn die Funktion niemals beendet wird - warum sollte ich sie
> beschleunigen wollen?

Kaj schrieb:
> More importantly, it helps avoid spurious warnings of uninitialized
> variables.

Das ist denke ich eher der Punkt.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Jens schrieb:
> static void function(uint8_t x, uint8_t y) __attribute__((noreturn));

Eine Funktion, der man Argumente übergibt und die nur einmal aufgerufen 
werden kann, macht wenig Sinn.
Vermutlich ist sie in Assembler geschrieben, d.h. das RET steht als 
Instruktion am Ende.
Besser schreibt man daher: __attribute__((naked))

von Theor (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Sven B. schrieb:
> Walter T. schrieb:
>> Denn Sinn dahinter habe ich allerdings nie verstanden (außer bei
>> main()). Wenn die Funktion niemals beendet wird - warum sollte ich sie
>> beschleunigen wollen?
>
> Kaj schrieb:
>> More importantly, it helps avoid spurious warnings of uninitialized
>> variables.
>
> Das ist denke ich eher der Punkt.

Magst Du dazu vielleicht eine Erklärung geben? Ein Beispiel? Einen Link?
In welcher Konstellation kann es fälschlicherweise eine Warnung vor 
uninitialisierten Variablen geben?

von Sven B. (scummos)


Bewertung
0 lesenswert
nicht lesenswert
int a;
if ( error ) {
  fatal("error occured");
}
else {
  a = 3;
}
print(a)
oder sowas in die Richtung?

von Kaj (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Eine Funktion, der man Argumente übergibt und die nur einmal aufgerufen
> werden kann, macht wenig Sinn.
Das macht sogar sehr viel Sinn.
Beispiel: Ein Thread der von der von einer Schnittstelle liest.
void read(queue) __attribute__((noreturn))
{
    // reads endless
    while (true) {
        x = read_data()
        queue.push(x)
    }
}

Warum macht es keinen Sinn der Funktion Argumente zu geben?
Und warum sollte ich die Funktion mehrfach aufrufen koennen? (Was ja 
trotzdem geht, naemlich als Thread)

Peter D. schrieb:
> Vermutlich ist sie in Assembler geschrieben, d.h. das RET steht als
> Instruktion am Ende.
> Besser schreibt man daher: __attribute__((naked))
Unsinn. Voellig verschiedene Paar Schuhe.

Walter T. schrieb:
> Wenn die Funktion niemals beendet wird - warum sollte ich sie
> beschleunigen wollen?
Wenn die Funktion nicht beendet wird, brauchst du die Ruecksprungadresse 
nicht speichern.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Kaj schrieb:
> Das macht sogar sehr viel Sinn.

Man kann natürlich viel spekulieren. Für mich klingt das nach Position 
setzen (x,y), d.h. sie wird sehr wohl mehrfach aufgerufen und muß daher 
auch zurück kehren. Grafikfunktionen in Assembler sind durchaus 
gebräuchlich, um sie schneller zu machen.

Kaj schrieb:
> Wenn die Funktion nicht beendet wird, brauchst du die Ruecksprungadresse
> nicht speichern.

Das wäre dann ein Jump. Funktionsaufrufe sind aber immer Calls, d.h. die 
CPU sichert immer den PC.

von Theor (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Also, es gibt erstmal diese Attribut. Schön.

Der Sinn erschliesst sich mir aber auch nicht so recht.

Das Folgende nur der Diskussion halber. Wer die Verwendung für 
angebracht hält mag es verwenden.

Es liegt vielleicht an meiner mangelnder Phantasie. Bzw. umgekehrt 
daran, dass ich für die zwei (im den Dokumentationen genanten Fälle) 
bisher genug Phantasie :-) hatte und alternative Forumulierungen 
benutze, die dieses Attribut von vorne herein unnötig machen.

1. Vermeidung von Tail-Calls: Falls Funktionen nicht zurückkehren (wie 
etwa exit()), dann schreibe ich den Code so, dass danach nicht etwa noch 
andere Anweisungen stehen. D.h. eine evtl. Umstellung von Anweisungen, 
so dass eine nicht-zurückkehrende Funktion nach diesen Anweisungen 
ausgeführt werden könnte, und also deren Seiteneffekte unbeabsichtigt 
wirksam werden, gibt es in meinem Code garnicht.

2. Vermeidung von Überflüssigen Warnungen vor uninitialisierten 
Variablen: Ich verwende Variablen (Deklarationen und als Teilausdrücke) 
überhaupt nur in den Verzeigungen, in denen der Programmablauf 
garantiert zu diesen Anweisungen führt.

Als Beispiel wandle ich den Code von Sven ab. (Sorry, Sven. Ich bin Dir 
dankbar, dass Du überhaupt geantwortet hast. Nichts für ungut).
f () {
  if ( error ) {
    fatal("error occured"); // i assume that fatal is meant to not return
  }
  else {
    int a;
    a = 3;
    print(a)
  }

 return; // just to make it explicit that this very function is not subject to not_return
}

Wäre interessant mal produktiven Code (etwa aus einem 
Open-Source-Projekt) zu sehen, der das Attribut verwendet.

von Bauform B. (bauformb)


Bewertung
0 lesenswert
nicht lesenswert
Man muss hier Mikrocontroller und Rechner mit "richtigem" Betriebssystem 
unterscheiden. Bei letzteren macht main() durchaus ein return und 
liefert einen Status. Der wird vom Betriebssystem an den Aufrufer (z.B. 
eine shell) des Programms weitergegeben.

Wenn der Benutzer das Programm mit falschen Parametern aufruft, kann es 
kaum mehr als eine Fehlermeldung ausgeben und abbrechen. Das geht z.B. 
mit exit(EXIT_FAILURE) und bei der Funktion ist das Attribut ja wohl 
angebracht. Das printf() für die Meldung und das exit() werden gerne 
zusammen in eine eigene Funktion wie die fatal() von Sven verpackt. Die 
macht dann auch kein return und bekommt logischerweise auch dieses 
Attribut.

Bei uC mit Multitasking gilt das genauso, nur bei einfachen 
uC-Programmen gibt es wenig Anwendungen. Eine Funktion könnte in einer 
Endlosschleife auf einen Watchdog-Reset warten. Einfache Fault-Handler 
verdienen sicher auch das Attribut. Meine crt0 hat ein _attribute_ 
((naked, noreturn)). Das finde ich total angemessen, wohin sollte die 
zurückkehren?

von imonbln (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Theor schrieb:
> Wäre interessant mal produktiven Code (etwa aus einem
> Open-Source-Projekt) zu sehen, der das Attribut verwendet.

Der Linux Kernel setzt das, an verschiedenen Stellen ein. meist hinter 
dem define __noreturn.

von Theor (Gast)


Bewertung
0 lesenswert
nicht lesenswert
imonbln schrieb:
> Theor schrieb:
>> Wäre interessant mal produktiven Code (etwa aus einem
>> Open-Source-Projekt) zu sehen, der das Attribut verwendet.
>
> Der Linux Kernel setzt das, an verschiedenen Stellen ein. meist hinter
> dem define __noreturn.

Ah. Guck mal an. Danke.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.