Forum: PC-Programmierung attribute noreturn


von Jens (Gast)


Lesenswert?

Hallo,

ich sehe gerade bei einer static void Function in C das attribute 
"noreturn".
1
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)


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
1
 For example, you can use attributes to specify that a 
2
function never returns (noreturn),

von Kaj (Gast)


Lesenswert?

https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
1
noreturn
2
3
    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,
4
5
    void fatal () __attribute__ ((noreturn));
6
7
    void
8
    fatal (/* … */)
9
    {
10
      /* … */ /* Print error message. */ /* … */
11
      exit (1);
12
    }
13
14
    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.
15
16
    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.
17
18
    In order to preserve backtraces, GCC will never turn calls to noreturn functions into tail calls.
19
20
    Do not assume that registers saved by the calling function are restored before calling the noreturn function.
21
22
    It does not make sense for a noreturn function to have a return type other than void.

von Walter T. (nicolas)


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)


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)


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)


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)


Lesenswert?

1
int a;
2
if ( error ) {
3
  fatal("error occured");
4
}
5
else {
6
  a = 3;
7
}
8
print(a)
oder sowas in die Richtung?

von Kaj (Gast)


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.
1
void read(queue) __attribute__((noreturn))
2
{
3
    // reads endless
4
    while (true) {
5
        x = read_data()
6
        queue.push(x)
7
    }
8
}

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)


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)


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).
1
f () {
2
  if ( error ) {
3
    fatal("error occured"); // i assume that fatal is meant to not return
4
  }
5
  else {
6
    int a;
7
    a = 3;
8
    print(a)
9
  }
10
11
 return; // just to make it explicit that this very function is not subject to not_return
12
}

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

von Bauform B. (bauformb)


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)


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)


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.

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.