Hallo, zunächst ich habe mir das Programmieren vor ca 3 Jahren selber beigebracht. Nach dem ich immer mehr dazu lerne und meine Projekte immer größer und komplexer werden versuche ich von globalen variablen weg zu kommen. Jedoch hatte ich bis her die Befürchtung,das Prozessor Laufzeit verloren geht, wenn ich eine Funktion mit Übergabe-Parameter erstelle. Nun meine Frage, wir später auf dem Prozessor dann für die Funktion eine zusätzliche variable erzeugt oder wird der Funktion nur die Adresse der Variablen übergeben, sodass die Funktion weiß mit welchen Variablen sie Arbeiten soll Über eine Antwort würde ich mich freuen. Grüße Basti
Guten Morgen, deine Frage ist leider noch zu allg. gefasst, da es hunderte Programmiersprachen und Kompilerbauer und Komputer gibt. Bitte spezifiziere deine Frage und stelle auch noch Beispielcode ein, dann kann man darauf eingehen.
Sebastian B. schrieb: > Jedoch hatte ich bis her die Befürchtung,das Prozessor Laufzeit verloren > geht, wenn ich eine Funktion mit Übergabe-Parameter erstelle. Das stimmt auch. Die Stackverwaltung braucht Rechenzeit. Die letztendlich alleinig interessanten Fragen sind andere: 1. passt das Programm wenn es fertig ist noch in den uC? Und: 2. ist es schnell genug? Wenn diese beiden Fragen mit JA beantwortet werden können, dann ist jede Sorge um die Programmeffizienz uninteressant. > Nun meine Frage, wir später auf dem Prozessor dann für die Funktion eine > zusätzliche variable erzeugt oder wird der Funktion nur die Adresse der > Variablen übergeben, sodass die Funktion weiß mit welchen Variablen sie > Arbeiten soll Zeig mal ein Beispiel, das dazu passt.
:
Bearbeitet durch Moderator
Sebastian B. schrieb: > Jedoch hatte ich bis her die Befürchtung,das Prozessor Laufzeit verloren > geht, wenn ich eine Funktion mit Übergabe-Parameter erstelle. RISC-artige Architekturen wie AVR, ARM oder PIC32 tun sich mit Parameterübergabe leichter als mit globalen Variablen. > Nun meine Frage, wir später auf dem Prozessor dann für die Funktion eine > zusätzliche variable erzeugt oder wird der Funktion nur die Adresse der > Variablen übergeben, sodass die Funktion weiß mit welchen Variablen sie > Arbeiten soll In FORTRAN wird die Adresse übergeben, in C der Wert wenn es kein Array ist.
Ich programmiere in C Bsp. in beiden Funktionen soll die Variable bearbeitet werden. ich habe eine Globale Variable (var_glob) und eine lokale (var_loc)
1 | void funktion1(void) |
2 | {
|
3 | var_glob ++; |
4 | }
|
5 | |
6 | int funktion2 (int XY) |
7 | {
|
8 | XY ++; |
9 | return XY; |
10 | }
|
11 | |
12 | Main
|
13 | {
|
14 | funktion1(); |
15 | var_loc = Funktion2(var_loc); |
16 | }
|
meine Frage ist ob beim Funktionsaufruf von Funktion 2 im Prozessor eine 2. Variable erzeugt wird, die zunächst mit der lokalen Variablen gleichgesetzt und so eine bestimmt anzahl von Taktzyklen und zusätzlich RAM braucht oder dies nur dazu ist, dass es übersichtlicher wird. Ich hoffe das meine Frage etwas anschaulicher geworden ist
:
Bearbeitet durch Moderator
Lothar M. schrieb: > Das stimmt auch. Die Stackverwaltung braucht Rechenzeit. Vorausgesetzt es findet überhaupt eine Stackverwaltung statt. Bei Parameterübergabe oder Variablen in Registern ist das nicht notwendigerweise der Fall. Oft nur in Form von Register-Save/Restore, wenn in der Funktion wiederum Funktionen aufgerufen werden.
Wie kommt es das Globale Variablen schlechter verarbeitet werden können als lokale?
Sebastian B. schrieb: > Wie kommt es das Globale Variablen schlechter verarbeitet werden können > als lokale? Parameter und lokale Variablen liegen oft in Registern. Zugriffszeit 0. Selbst wenn sie auf dem Stack liegen können sie relativ zum Stack- oder Framepointer meist direkt adressiert werden, da die Distanz dazu gering ist und direkt im Lade/Speicherbefehl codiert werden kann. Globale und statische Variablen hingegen haben eine recht breite Adresse, die viel Platz benötigt und insbesondere bei 32-Bit RISCs nicht in einem Befehl direkt verarbeitet werden kann. Bei den Cortex M3 (Thumb2) sind dann auf Zeit optimiert 3 Befehle nötig. 2 laden die Adresse in ein Register und einer spricht darüber den Speicher an. Auf Platz optimiert ist es zwar etwas kürzer, sorgt aber ggf. für etliche Waitstates aufgrund Datenzugriffs auf das Flash-ROM. In beiden Fällen fällt ein zusätzlich verwendetes Register an. Anders sieht es beispielsweise bei den 8-Bit PICs aus. Die verfügen entweder überhaupt nicht über die Fähigkeit, einen Stack anzusprechen, oder Zugriff und Verwaltung davon sind relativ aufwändig. Optimierungsstrategien für solche nicht auf C optimierte Architekturen sind daher deutlich anders als für Standardarchitekturen.
:
Bearbeitet durch User
Sebastian B. schrieb: > Globale Variablen .... als lokale Ob man etwas global, oder lokal macht, sollte man davon abhängig machen, welche Sichtbarkeit man der Variablen geben muss. Immer wieder eine gute Strategie: Kapseln! Um die Taktzyklen, oder den Speicherbedarf, kann man sich einen Kopf machen, wenn es eng wird.
Grundsätzlich gilt: Auf Sprachebene sollte man sich keine Gedanken über Optimierung machen, sondern auf gute Strukturierung achten. Aus zwei Gründen: - Erstens ist der allermeiste Code in keiner Weise performance-kritisch. Ob er doppelt oder zehnmal so lange braucht wie die optimale Lösung, hat auf die gefühlte Effizienz des Programms keinerlei Einfluss. Setze also die Zeit zum Optimieren genau dort ein, wo du tatsächlich Performance-Probleme identifiziert hast. - Der Compiler optimiert extrem stark und intelligent. Er weiss viel besser als du, wie man bestimmte Sprachkonstrukte in effizienten Maschinencode umwandelt. Erkläre dem Compiler auf möglichst "verständliche" Art, was du haben möchtest und er wird das richtige daraus machen.
Vielen dank für die vielen, schnellen und ausführlichen Beiträge :) Das die Lokalen Variablen in Registern gespeichert werden ist praktisch. vielen dank grüße basti
Sebastian B. schrieb: > Das die Lokalen Variablen in Registern gespeichert werden Nur wenn es welche gibt. Bei 8-Bit PICs und Freescales gibts keine und bei den 16-Bit Renesas (R8C/M16C/M32C) zu wenige. Um ein paar Beispiele zu nennen.
:
Bearbeitet durch User
Sebastian B. schrieb:
1 | > void funktion1(void) |
2 | > { |
3 | > var_glob ++; |
4 | > } |
5 | >
|
6 | > int funktion2 (int XY) |
7 | > { |
8 | > XY ++; |
9 | > return XY; |
10 | > } |
> meine Frage ist ob beim Funktionsaufruf von Funktion 2 im Prozessor eine > 2. Variable erzeugt wird, die zunächst mit der lokalen Variablen > gleichgesetzt und so eine bestimmt anzahl von Taktzyklen und zusätzlich > RAM braucht oder dies nur dazu ist, dass es übersichtlicher wird. Du machst dir Gedanken um nichts. Ein vernünftiger Compiler (das sind heutzutage fast alle) wird dir für beide Funktionen praktisch identischen Code generieren. Die Variable wird sich vor dem Funktionsaufruf in einem Register befinden. Für den Aufruf von funktion2 wird die Variable in einem Register übergeben und in einem Register (meist dem gleichen) zurückgegeben. Der Compiler wird, wenn er clever ist, jegliche Register-zu-Register Transfers einsparen, indem er die Variable von Anfang an in das richtige Register lädt. Und eine so kurze popelige Funktion wie oben wird der Compiler fast sicher sowieso inlinen, also gar keinen Funktionsaufruf machen sondern den Rumpf der Funktion dort wo sie aufgerufen wird, einfügen. Du machst dir aber sowieso die falschen Gedanken. Ein Ziel bei der Entwicklung höherer Programmiersprachen ist immer auch eine bessere Lesbarkeit des Programmcodes. Und Lesbarkeit meint nicht nur lesbar, sondern auch: von vorn herein leichter schreibbar, leicher debugbar, leicher zu warten und zu pflegen. Und die Vermeidung globaler Variablen dient ebenfalls diesem Zweck. Wenn du in einer Hochsprache programmierst, dann sollte die Effizienz des vom COmpiler erzeugten Codes so ziemlich das Letzte sein, an das du beim Schreiben des Programmes denkst. Achte lieber darauf daß es 1. korrekt und 2. lesbar ist. Optimierung auf Geschwindigkeit findet meist auf höheren Ebenen statt, z.B. indem man einen anderen Algorithmus implementiert. Mikrooptimierung wie du sie hier betreiben willst, ist in 99% aller Fälle vollkommen unnötig. Anders ausgedrückt: Quicksort ist nicht deswegen schneller als Bubblesort, weil es globale statt lokaler Variablen verwendet, sondern weil es einen [für größere Datenmengen] besseren Algortihmus verwendet.
Lothar M. schrieb: > Die letztendlich alleinig interessanten Fragen sind andere: 1. passt das > Programm wenn es fertig ist noch in den uC? Und: 2. ist es schnell > genug? Beides stellst Du zuallererst mit (gutem) Assembler sicher.
Moby A. schrieb: > Lothar M. schrieb: >> Die letztendlich alleinig interessanten Fragen sind andere: 1. passt das >> Programm wenn es fertig ist noch in den uC? Und: 2. ist es schnell >> genug? > Beides stellst Du zuallererst mit (gutem) Assembler sicher. Das ist hier in keinster Weise die Frage! Ich werde in Zukunft jeden Versuch, einen Thread zu entführen einfach per Löschung unterbinden. Leute, tut mir leid für eure Zeit zum Schreiben der Beiträge, die auf diesen Trollaufruf folgten. Lasst es einfach bleiben und meldet solche Entführungsversuche per Knopfdruck.
Axel S. schrieb: > Optimierung auf Geschwindigkeit findet meist auf höheren Ebenen statt, > z.B. indem man einen anderen Algorithmus implementiert. Mikrooptimierung > wie du sie hier betreiben willst, ist in 99% aller Fälle vollkommen > unnötig. Anders ausgedrückt: Quicksort ist nicht deswegen schneller als > Bubblesort, weil es globale statt lokaler Variablen verwendet, sondern > weil es einen [für größere Datenmengen] besseren Algortihmus verwendet. Mikrooptimierung ist schon wichtig, aber man macht es nicht von Hand, sondern der Compiler macht es. Wenn man beispielsweise eine mathematische Formel in einer Schleife auswertet, so gewinnt man Zehnerpotenzen an Performance dadurch, dass die einzelnen Funktionen ge-inlined und nicht separat aufgerufen werden.
P. M. schrieb: > Axel S. schrieb: >> Optimierung auf Geschwindigkeit findet meist auf höheren Ebenen statt, >> z.B. indem man einen anderen Algorithmus implementiert. Mikrooptimierung >> wie du sie hier betreiben willst, ist in 99% aller Fälle vollkommen >> unnötig. Anders ausgedrückt: Quicksort ist nicht deswegen schneller als >> Bubblesort, weil es globale statt lokaler Variablen verwendet, sondern >> weil es einen [für größere Datenmengen] besseren Algortihmus verwendet. > > Mikrooptimierung ist schon wichtig, aber man macht es nicht von Hand, > sondern der Compiler macht es. Und man betreibt natürlich auch nicht sinnlos kompliziertes Programmieren, sondern benutzt normales, übliches Vorgehen. In diesem Sinne muss man ein generelles "mach dir keine Sorgen, der Compiler wirds schon richten" auch zurechtrücken. Eng damit im Zusammenhang steht natürlich auch, dass man seine Programmiersprache einigermassen beherrscht. Wer von seiner Sprache gerade mal 10% des Sprachumfangs kennt, und das auch nur mehr schlecht als recht, wird nicht viel zu Stande bringen - mit oder ohne Mikrooptimierung.
P. M. schrieb: > Axel S. schrieb: >> Optimierung auf Geschwindigkeit findet meist auf höheren Ebenen statt, >> z.B. indem man einen anderen Algorithmus implementiert. Mikrooptimierung >> wie du sie hier betreiben willst, ist in 99% aller Fälle vollkommen >> unnötig > Mikrooptimierung ist schon wichtig, aber man macht es nicht von Hand, > sondern der Compiler macht es. Ich dachte es wäre im Kontext klar gewesen, daß ich manuelle Mikro- optimierung gemeint habe. Und nicht das was der Compiler tut.
Axel S. schrieb: > Ich dachte es wäre im Kontext klar gewesen, daß ich manuelle Mikro- > optimierung gemeint habe. Und nicht das was der Compiler tut. Ich habe es vermutet, ja. Wollte aber sicher gehen und noch ein paar Worte anfügen, da der TO sich damit scheinbar noch wenig auskennt. Karl H. schrieb: > Eng damit im Zusammenhang steht natürlich auch, dass man seine > Programmiersprache einigermassen beherrscht. Wer von seiner Sprache > gerade mal 10% des Sprachumfangs kennt, und das auch nur mehr schlecht > als recht Richtig. Besonders sollte man auch wissen, was in einer Sprache teuer/problematisch ist. In C/C++ beispielsweise dynamische Speicherallokation oder versehentliches pass-by-reference von grossen Objekten. Genau aus diesem Grund halte ich es für sinnvoll, eine Sprache tiefer kennen zu lernen als bloss die Sprachkonstrukte und Bibliotheksaufrufe kennen zu lernen. Man muss wissen, was unter der Haube passiert.
P. M. schrieb: > oder versehentliches pass-by-reference von grossen Objekten. War hoffentlich andersrum gemeint. Ich finde die Idee, grosse Objekte per Referenz zu übergeben, durchaus vernünftig.
:
Bearbeitet durch User
A. K. schrieb: > P. M. schrieb: >> oder versehentliches pass-by-reference von grossen Objekten. > > War hoffentlich andersrum gemeint. Ich finde die Idee, grosse Objekte > per Referenz zu übergeben, durchaus vernünftig. Aber klar :-) Versehentliches pass-by-value sollte es heissen. Autsch...
A. K. schrieb: > Parameter und lokale Variablen liegen oft in Registern. Zugriffszeit 0. Hehe.. du hast heut wohl nen eher schlechten Tag. Von wegen Zugriffszeit 0 - das Argument muß ja erstmal dort hinein kommen. Ich halte das Herumgefummel mit Funktionsargumenten dort, wo es nicht sein muß, für einen ziemlich überflüssigen Kropf. Es bringt nix und kostet bloß bei jedem Aufruf der betreffenden Funktion das Laden des Argumentes. Viel wichtiger als all das Grübeln über globale Variablen oder nicht ist es, eine Firmware sinnvoll zu modularisieren, so daß man nicht das ganze Gekröse an Variablen und anderem Krempel überall um die Ohren hat. Was dann an globalen Variablen wirklich noch übrig bleibt, ist fast immer nur ganz wenig - und das Wenige hat dann seine Berechtigung. W.S.
A. K. schrieb: > Parameter und lokale Variablen liegen oft in Registern. Zugriffszeit 0. Nanana. Ganz so einfach ist das natürlich nicht. Das hängt leider von sehr vielen Variablen ab. Klar: Sprache, Compiler, Optimierungslevel. Darüber hinaus aber auch noch massiv vom Zielsystem. Wenn das einfach mal nur wenige Register besitzt, ist nicht damit zu rechnen, daß viele für die Parameterübergabe genutzt werden (können). Und leider setzt bei den oft relativ starren Algorithmen der Codegeneratoren die Stacknutzung oft schon ein, lange bevor die Register "alle" sind. Abgesehen davon: Natürlich ist auch ein Registerzugriff nicht zum Nulltarif zu bekommen. Nicht mal in Assembler...
W.S. schrieb: > Hehe.. du hast heut wohl nen eher schlechten Tag. Von wegen Zugriffszeit > 0 Welche Zahl wär dir lieber, wenn man mal davon ausgeht, dass RAM bei µCs einen Takt Zugriffszeit hat? Ein Register hat mindestens bei den RICSs weniger Zugriffszeit als das RAM und negativ wirds nicht. Bei CISCs mit darauf optimierter Pipelining kann man zwar was einsparen, aber so arg viele µCs dieser Bauart fallen mir grad nicht ein. > das Argument muß ja erstmal dort hinein kommen. Korrekt. Das ist aber hauptsächlich dann von Vorteil, wenn die Funktion die Variable überhaupt nicht benötigt. Ich hatte oben schon aufgeführt, dass ich mich in dieser Betrachtung eher auf registerorientierte Architekturen beziehe. Bei 8-Bit PIC/8051/68xx kann die Sache anders ausgehen. > Ich halte das Herumgefummel mit Funktionsargumenten dort, wo es nicht > sein muß, für einen ziemlich überflüssigen Kropf. Es bringt nix und > kostet bloß bei jedem Aufruf der betreffenden Funktion das Laden des > Argumentes. Klar, 0 Parameter sind schneller als 1 Parameter. Aber das ist hier nicht die Alternative. Sondern Parameter gegenüber globaler Variable. Und da hat der (skalare) Parameter noch einen weiteren Vorteil, wenn davon nirgends die Adresse verlangt wird: Weder kann Aliasing auftreten, noch wird er in einem Unterprogramm verändert. > Viel wichtiger als all das Grübeln über globale Variablen oder nicht ist > es, eine Firmware sinnvoll zu modularisieren, so daß man nicht das ganze > Gekröse an Variablen und anderem Krempel überall um die Ohren hat. Modularisierung vermeidet keine Variablen, sondern platziert sie übersichtlicher im Quellcode und adressiert sie evtl anders. Das kann in Verbindung mit struct/class zu relativer Adressierung von Variablen führen, die sonst absolut adressiert würden. Was meist ein klarer Vorteil ist, es sei denn der Prozessor tut sich damit schwer. Nur hatte ich diese bei µC-Programmierung in C++ häufiger als in C verbreitete Technik hier erst einmal aussen vor gelassen.
c-hater schrieb: > Wenn das einfach mal nur wenige Register besitzt, Ja, aber das hatte ich auch schon ausdrücklich erwähnt.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.