Hallo Leute,
wollte einfach mal Fragen ob es Sinn macht (aus sicht der
Ausführgeschwindigkeit) bei einem Cortex M3 (oder generell bei 32-Bit
Prozessoren) Strukturen per Reference anstatt per Value zu übergeben?
Beispiel:
Rudolf H. schrieb:> wollte einfach mal Fragen ob es Sinn macht (aus sicht der> Ausführgeschwindigkeit) bei einem Cortex M3 (oder generell bei 32-Bit> Prozessoren) Strukturen per Reference anstatt per Value zu übergeben?
Das hat nichts mit Cortex M3 oder 32-Bit zu tun. Wenn du die Struktur
per Value übergibst, kommt eine Kopie komplett auf den Stack und dass
will keiner. Außer es ist gezielt so gewollt. Es geht dabei nicht
vorrangig um die Ausführungsgeschwindigkeit.
Spätestens wenn in der Funktion die Variablen der Struktur geändert
werden merkst du den Unterschied. Über den Pointer wird die übergebene
Struktur geändert. Per Value passiert die Änderung in der Kopie auf dem
Stack und nur dort.
old man schrieb:> Per Value passiert die Änderung in der Kopie auf dem> Stack und nur dort.
Das ist mir schon klar, aber wenn nur lesend auf die Struktur
zugegriffen wird ist dies egal (habe ich nicht klar hineingeschrieben,
sorry!). Mich interessiert konkret, ob es sich aus Sicht der
Geschwindigkeit lohnt, Pointer zu verwenden (diese bringen ja die Gefahr
von ungültigen Pointern --> Absturzgefahr mit sich)?
(Variante 1 ist nicht per Reference, sondern per Pointer.)
Die Übergabe per Pointer ist speichersparender. Es können aber die
Strukturelemente in der Funktion verändert werden. Soll das verhindert
werden, per 'const' übergeben.
Zusatz: Die Struktur sollte schon existieren. Wenn du per Value
übergibst, würde in dem Fall eben irgendwelcher Mist drinstehen. Also
egal.
noch zusätzlich:
'per reference' wird ja nicht mal mehr der Zeiger übergeben. Aber auch
gegen Überschreiben (sicherheitshalber) mit 'const' deklarieren!
[ das ist ein Beispiel für das speicherverschwendende C++ ;-) ]
Ralf G. schrieb:> noch zusätzlich:> 'per reference' wird ja nicht mal mehr der Zeiger übergeben. Aber auch> gegen Überschreiben (sicherheitshalber) mit 'const' deklarieren!>> [ das ist ein Beispiel für das speicherverschwendende C++ ;-) ]
Bitte was? Die Referenzen bei Funktions-Argumenten in C++ funktionieren
auf Maschinenebene exakt wie Pointer. Es wird kein Bit mehr Speicher
verbraucht als bei C-Pointern. Was ich zum "speicherverschwenden von
C++" sonst noch zu sagen habe kannst du dir ja denken, das wird in
diesem Forum ja eh kollektiv weggefiltert.
Rudolf H. schrieb:> Strukturen per Reference anstatt per Value zu übergeben?
Das hängt von der Größe ab. 5 Register (R0-R5) a 32bit werden (zumindest
beim EABI) für die Übergabe von Argumenten verwendet. Wenn der struct da
komplett hineinpasst dauert der Aufruf zwar ein paar Takte länger, dafür
ist der Zugriff auf die Werte von innerhalb der aufgerufenen Funktion
schneller, da die Indirektion entfällt. Falls die aufrufende Funktion
außerdem nicht viel mit dem struct anstellt, kann dieser ggf. komplett
in den Registern verbleiben und muss gar nicht erst auf den Stack gelegt
werden, und der Aufruf "by value" muss gar nichts mehr machen, während
der "by Reference" das Ablegen des structs auf den Stack erzwingen
würde. Wenn man die Originalwerte verändern will könnte man in Erwägung
ziehen den veränderten struct zurückzugeben (statt eine Referenz/Pointer
zu verwenden) - aus den gleichen Gründen wie oben kann das effizienter
sein. Das ganze hängt von einigen Faktoren ab, es hilft wie immer:
ausprobieren & disassemblen.
Dr. Sommer schrieb:> Bitte was? Die Referenzen bei Funktions-Argumenten in C++ funktionieren> auf Maschinenebene exakt wie Pointer. Es wird kein Bit mehr Speicher> verbraucht als bei C-Pointern.
Ich meinte: Es könnte sogar noch weniger als der Pointer dabei
rauskommen! Eigentlich kann die Funktion die Variable doch 'wie global
verwenden'. Hat eben bloß einen anderen Namen.
Ralf G. schrieb:> [ das ist ein Beispiel für das speicherverschwendende C++ ;-) ]
^^^
Ralf G. schrieb:> Eigentlich kann die Funktion die Variable doch 'wie global> verwenden'. Hat eben bloß einen anderen Namen.
Es sei denn die Funktion wird mehr als 1x und mit verschiedenen
structs als Argumenten aufgerufen (dafür sind Funktionen da), dann
braucht man für jeden struct seinen eigenen Speicher und kann nicht
einfach alles in eine einzelne globale Variable packen.
Ich habe in meinem Projekt einige Klassen die nur einen einzelnen
Integer enthalten der auch noch "const" ist. Diese Klassen alle per
Value anstatt per (const) Reference/Pointer zu übergeben macht den Code
viel kleiner und schneller.
PS: Ich glaube es waren doch nur 4 Register, kann ich grad nicht
nachgucken
Um das mal nachzuvollziehen, habe ich's gerade mal mit der Übergabe von
Ports simuliert. Und da fiels mir dann wie Schuppen aus den Haaren:
Dr. Sommer schrieb:> Es sei denn die Funktion wird mehr als 1x und mit verschiedenen> structs als Argumenten aufgerufen (dafür sind Funktionen da)
(Verdammt. Wozu braucht man denn da jetzt solche Referenzen?
Edit: ... Außerhalb von Funktionen)
Ralf G. schrieb:> (Verdammt. Wozu braucht man denn da jetzt solche Referenzen?
Referenzen sind praktisch Pointer, die bezüglich des Beschreibens
eingeschränkt sind. Daher verwendet man sie dort, wo man Pointer
verwenden würde und diese Einschränkungen passen. Durch diese
Einschränkung ergibt sich eine Zusicherung beim Lese-Zugriff, die die
Programmierung vereinfacht, da es weniger Eventualitäten zu beachten
gibt.
Konkret: Eine Referenz kann nicht auf "nichts" (NULL) zeigen und kann
ihr Ziel auch nicht ändern. Das heißt man braucht nicht auf NULL zu
prüfen und kann annehmen dass sie immer auf das selbe Objekt zeigt.
Die abgewandelte Syntax (zum Pointer) sollte diese Vereinfachung
deutlich machen, ist aber nicht unbedingt so glücklich gewählt...
Referenzen sind also nur ein Mittel des Programmierers, um dem Compiler
seine Absicht mitzuteilen und von diesem auch daran erinnert zu werden,
sich daran zu halten; ähnlich zu "const". Auf Maschinenebene sind
Referenzen einfach Pointer, können aber leicht innerhalb einer Funktion
komplett wegoptimiert werden.
arc net schrieb:> nichts leichter als das...
Das ist undefiniertes Verhalten. Bevor man einer Referenz einen
dereferenzierten Pointer zuweist muss man sie natürlich auf Gültigkeit
(!= NULL) prüfen:
1
voidTestRef(int&anInt){
2
anInt=123;
3
}
4
5
int*array[4]={nullptr,nullptr,nullptr,nullptr};
6
if(array[3]!=NULL)
7
TestRef(*array[3]);
PS: "NULL" ist deprecated und sollte durch nullptr ersetzt werden.
Dieses ist auch zu jedem Pointertyp konvertierbar.
Dr. Sommer schrieb:> arc net schrieb:>> nichts leichter als das...> Das ist undefiniertes Verhalten. Bevor man einer Referenz einen> dereferenzierten Pointer zuweist muss man sie natürlich auf Gültigkeit> prüfen
Selbst dann kann später im Programm irgendetwas die Elemente des Arrays
aus dem Beispiel auf Null setzen...
arc net schrieb:> Selbst dann kann später im Programm irgendetwas die Elemente des Arrays> aus dem Beispiel auf Null setzen...
Das ändert nichts, da die Referenz nichts mehr mit dem Array zu tun hat,
sondern auf das Ziel des Pointers aus dem Array verweist - den hast du
ja schließlich dereferenziert, er ist also "verschwunden".
Mitleser schrieb:> Immer wieder nett wie die Experten sich kabbeln und jeder für sich das> absolute Wissen in Anspruch nimmt. Wirklich drollig.
Das muss so sein. Wenn alle einer Meinung sind, ist etwas faul.
Mitleser schrieb:> Immer wieder nett wie die Experten sich kabbeln und jeder für sich das> absolute Wissen in Anspruch nimmt. Wirklich drollig.
Der Vorteil bei dieser Art Diskussion ist, dass man einfach ausprobieren
kann wie es richtig ist :o)
http://xkcd.com/386/