Funktionsparameter effizient anlegen
-
Hallo Leute,
in einer Funktion, die im Schnitt vll. alle zwei ms aufgerufen wird, und die möglichst schnell laufen soll, benötige ich ein 10er array vom typ einer struct, die ich vorher per typedef definiert habe.
Dieses Array könnte ich entweder so:
void foo (int Arg1, int Arg2, int Arg3) { static BAR * pfoobar = NULL; if (! foobar) test_struct = Calloc(10, sizeof(TEST)); }
oder so:
void foo (int Arg1, int Arg2, int Arg3) { struct BAR foobar[10]; }
erzeugen (und natürlich dann auch benutzen...).
Ist davon eine Variante vorzuziehen oder ist es egal, wie ich es mache?
Gruß
-
Die zweite Variante dürfte schneller sein, da das Array sofort auf dem Stack zu liegen kommt, während die erste immer Funktionsaufrufe für alloc und free benötigt. Natürlich darfst du das Array aus der zweiten Variante niemals an den Aufrufer zurückgeben...
-
Zooonk schrieb:
Natürlich darfst du das Array aus der zweiten Variante niemals an den Aufrufer zurückgeben...
Die erste besser auch nicht. Führt bloß zu Speicherlöchern und vielen Tränen.
-
besser ist es, den speicher außerhalb der funktion zu beschaffen und das array als parameter zu übergeben.
-
Vielleicht eine Kombination der beiden Varianten:
void foo (int Arg1, int Arg2, int Arg3) { static struct BAR foobar[10];
}
-
Belli schrieb:
Vielleicht eine Kombination der beiden Varianten:
void foo (int Arg1, int Arg2, int Arg3) { static struct BAR foobar[10];
}
Ihh! Jetzt ist die Funktion nicht mehr reentrant und nicht mehr cachelokal. Zwei Dicke Nachteile und kein Vorteil.
-
Das ist die erste Variante vom TE auch nicht.
-
Nathan schrieb:
Das ist die erste Variante vom TE auch nicht.
Ja, die ist ja auch Mist (was soll eigentlich dieses if?). Er soll unbedingt die zweite nehmen! Und falls er das Array aus der Funktion zurück geben möchte (es ist unklar, was er überhaupt mit dem Array machen möchte), dann soll er es so machen wie von xyz-offgeloggert0r vorgeschlagen.
-
Die Frage ist doch, muss die Funktion überhaupt reentrant sein? Da die erste vom TE vorgeschlagene Variante das nicht ist, gehe ich davon aus, dass das nicht erforderlich ist.
-
Belli schrieb:
Die Frage ist doch, muss die Funktion überhaupt reentrant sein? Da die erste vom TE vorgeschlagene Variante das nicht ist, gehe ich davon aus, dass das nicht erforderlich ist.
Selbst wenn nicht, ist die zweite Variante einfach nur schneller und zudem noch ohne weitere Kosten reentrant. static sollte man nur benutzen, wenn es für das Funktionieren wirklich absolut unerlässlich ist. Ganz besonders nicht für Mikrooptimierungen, denn es ist einfach ein Irrglaube, dass das Erzeugen von Variablen irgendwie Zeit bräuchte. Da gibt es nämlich gar nichts zu Erzeugen. Diese "Erzeugung" ist schlimmstenfalls ein Versetzen des Stackpointers am Funktionsbeginn um einen anderen Wert als er sonst sowieso schon versetzt worden wäre.
Mit dem static lebt hingegen die Variable in einem ganz anderen Speicherbereich als die anderen lokalen Variablen und es muss eine weitere Speicherseite in den Cache geladen werden die dort schlimmstenfalls 1. noch nicht drin war und 2. irgendwas anderem den Platz wegnimmt. Und es ist vermutlich auch nicht mehr möglich, dass die Variablen ganz wegoptimiert werden und selbst einfache Optimierungen werden erheblich erschwert oder verhindert.
Ich wette bei einem Performancevergleich würde die static-Version niemals schneller sein, vermutlich sogar einknicken.
-
Belli schrieb:
Die Frage ist doch, muss die Funktion überhaupt reentrant sein? Da die erste vom TE vorgeschlagene Variante das nicht ist, gehe ich davon aus, dass das nicht erforderlich ist.
Warum unnoetig Nachteile in Kauf nehmen, wenn Realisierungen mit allen Vorteilen soviel einfacher sind.
-
Richtig!
Ich bin (wohl irrtümlich (danke Seppj für die Erläuterung)) davon ausgegangen, dass es schneller ist, die Variable nur einmal (static) zu erzeugen.
-
Belli schrieb:
Richtig!
Ich bin (wohl irrtümlich (danke Seppj für die Erläuterung)) davon ausgegangen, dass es schneller ist, die Variable nur einmal (static) zu erzeugen.Genau das hatte ich auch erst gedacht, daher die Frage...
Danke für die Erläuterungen.
-
SeppJ schrieb:
Nathan schrieb:
Das ist die erste Variante vom TE auch nicht.
Ja, die ist ja auch Mist (was soll eigentlich dieses if?). Er soll unbedingt die zweite nehmen! Und falls er das Array aus der Funktion zurück geben möchte (es ist unklar, was er überhaupt mit dem Array machen möchte), dann soll er es so machen wie von xyz-offgeloggert0r vorgeschlagen.
Achja, und hierzu noch: Ich hatte wohl fälschlicherweise angenommen, dass der allozierte Speicher quasi auch static ist, da schließlich der Pointer static ist... Scheint nicht so zu sein...
-
Doch selbstverständlich. Via malloc/calloc angeforderter Speicher liegt auf dem Heap und steht zur Verfügung, bis er irgendwann mittels free wieder freigegeben wird - insofern schon mit static vergleichbar.
-
Dann wiederum verstehe ich nicht ganz, worauf die Frage
SeppJ schrieb:
(was soll eigentlich dieses if?)
zielt, da die if-Abfrage (wie die NULL-Initialisierung) ja schlicht dafür sorgt, dass das Calloc nur beim ersten Durchlauf ausgeführt wird und sowohl Pointer, wie auch Speicher, danach halt "da" sind.
Aber egal, solange gilt
SeppJ schrieb:
es ist einfach ein Irrglaube, dass das Erzeugen von Variablen irgendwie Zeit bräuchte
ist ja klar, wie das Ganze zu machen ist...
-
Naja, Du hättest einfach:
void foo (int Arg1, int Arg2, int Arg3) { static BAR * foobar = Calloc(10, sizeof(TEST)); // ... }
machen können ...
-
Ne, das hatte schon seinen Sinn; wenn ich es mache, wie Du sagst, kommt bei mir:
compiler schrieb:
error : static/external initializers must be constant expressions
-
Schock schrieb:
Ne, das hatte schon seinen Sinn; wenn ich es mache, wie Du sagst, kommt bei mir:
compiler schrieb:
error : static/external initializers must be constant expressions
Oh, ach ja.
Das geht ja nur in C++, nicht in C. Tut mir leid, dann war die if-Abfrage doch sinnvoll. Solche Detailsunterschiede bei wenig genutzten Sprachfeatures entfallen mir manchmal.
Aber, wie schon geklärt, sollte man diese Variante ohnehin nicht benutzen.
-
Okay, wusste ich auch nicht, dass das in C nicht klappt ...