Hallo,
ich habe ein kleines Problem. Ein Unterprogramm soll zwei Variablen
verändern, die ich ihr übergebe. Da viele verschiedene Variablen damit
geändert werden sollen, kann ich keine globalen Variablen benutzen.
1
unsignedchartype,length;
2
3
get_info(type,length);
4
5
// Hier sollen type und length nun verändert sein
6
7
[...]
8
9
voidget_info(type,length)
10
{
11
type=0x15;
12
length=0xFF;
13
}
Ich glaube da muss man irgendwie mit Pointern rumfuchteln .. aber ich
bin mir nicht sicher.
Bitte nicht schlagen, bin noch C-Anfänger.
E.M.
> Ich glaube da muss man irgendwie mit Pointern rumfuchteln ..
Genau. Du mußt Der Funktion nicht die Werte, sondern Adressen der
Variablen übergeben, also statt "get_info(type, length);" muß es sein
"get_info(&type, &length);".
In der Funktion kannste auf die Werte der übergebenen Variablen über
"dereferencing" zu greifen, *type liefert z.B. den Wert von type.
Am besten ein C pointer tutorial Deiner Wahl durchlesen.
Es geht auch mit ner Struktur aus 2 Variablen (oder mehr).
Das hat den Vorteil, daß der Compiler besser optimieren kann
(Registervariablen statt Pointer auf SRAM).
Das ist bei größeren Strukturen sehr ineffizient.
Hier wird mehrfach die gesamte Struktur kopiert, zunächst beim
Funktionsaufruf auf den Stack, danach bei der Zuweisung des
Rückgabewertes der Funktion an die Variable x.
Gerade hier ist die Verwendung von Pointern sehr zu empfehlen, weil da
gar nichts kopiert werden muss.
Rufus t. Firefly wrote:
> Das ist bei größeren Strukturen sehr ineffizient.
Kann man nicht so pauschal sagen.
Der GCC kann das sehr gut optimieren.
Der obige Code compiliert zu:
1
structtype_lengthget_info(structtype_lengthval)
2
{
3
val.type=0x15;
4
val.length=0xFF;
5
returnval;
6
}
7
ce:85e1ldir24,0x15;21
8
d0:9fefldir25,0xFF;255
9
d2:0895ret
Besser gehts nicht mal in Assembler.
Aber auch bei mehr Elementen, wenn die Register nicht mehr reichen, wird
es zumindest nicht größer als die Pointervariante.
Im Gegensatz dazu mit Pointer:
Und was geschieht, wenn die Struktur nicht mehr in ein paar Register
passt? Dann muss sie auf den Stack geschoben werden, und da fängt die
Kopiererei an.
Rufus t. Firefly wrote:
> Und was geschieht, wenn die Struktur nicht mehr in ein paar Register> passt? Dann muss sie auf den Stack geschoben werden, und da fängt die> Kopiererei an.
Der GCC mag seine Schwächen haben, aber oftmals ist er sehr clever.
Auch mit der Struktur im RAM ist er besser, da er dann nur über einen
Base-Pointer mit Displacement (0..63) zugreift.
Das ist natürlich viel effektiver, als für jede Variable ein extra
Pointer.
Und bei vielen Parametern ist die Pointerversion erst recht Schwachsinn.
Dann müssen ja nicht nur die Parameter, sondern auch die einzelnen
Pointer im RAM abgelegt werden.
Viele Paramter übergibt man daher nicht über einzelne Pointer, sondern
über eine Struktur oder ein Array (= Struktur aus gleichen Elementen).
Peter
> Viele Paramter übergibt man daher nicht über einzelne Pointer,> sondern über eine Struktur oder ein Array (= Struktur aus> gleichen Elementen).
Ja. Aber man übergibt nicht die Struktur, sondern einen Pointer darauf.
Eine Kopie der Struktur zu erzeugen, um diese einer Funktion zu
übergeben und diese Kopie nach Beendigung der Funktion wieder anderswo
hinzukopieren, das ist nicht effizient.
Vielen vielen Dank für eure Tipps!
Ich habe es jetzt mit Pointern auf eine Struct realisiert. Das finde ich
viel eleganter als meine anfängliche Idee.
E.M.
Rufus t. Firefly wrote:
> Ja. Aber man übergibt nicht die Struktur, sondern einen Pointer darauf.> Eine Kopie der Struktur zu erzeugen, um diese einer Funktion zu> übergeben und diese Kopie nach Beendigung der Funktion wieder anderswo> hinzukopieren, das ist nicht effizient.
Wenn man ihn mit Optimierung -O0 dazu zwingt, wird er eine Kopie
anlegen.
Ansonsten wird er schon selber den optimalen Zugriff finden, egal wie
man es hinschreibt.
Solche Zugriffsoptimierungen sind ja Brot und Butter jedes C++
Compilers.
Peter
> Ansonsten wird er schon selber den optimalen Zugriff finden,> egal wie man es hinschreibt.
Das nenne ich Gottvertrauen. Wenn der Code der Funktion und der Code des
Aufrufs in unterschiedlichen Übersetzungseinheiten zu finden sind, dann
dürfte der Optimierer recht wenig Chancen haben.
Rufus t. Firefly wrote:
> Das nenne ich Gottvertrauen. Wenn der Code der Funktion und der Code des> Aufrufs in unterschiedlichen Übersetzungseinheiten zu finden sind, dann> dürfte der Optimierer recht wenig Chancen haben.
Nö, mit Gottvertrauen hat das nichts zu tun.
Der Compiler hat feste Regeln, wie er Argumentenlisten verarbeitet, wenn
er sie nicht mehr direkt in Registern übergeben kann. Dann muß er einen
Pointer übergeben.
Er arbeitet also schon mit Pointern, auch wenn man es nicht als Pointer
hinschreibt.
Ob er nun eine Kopie anlegt oder sich nur intern merkt, daß die
Originaldaten read-only sind, müßte jemand ausprobieren, der Lust dazu
hat.
Peter