mikrocontroller.net

Forum: Compiler & IDEs Übergebene Variablen in Unterprogramm ändern?


Autor: E.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
unsigned char type, length;

get_info(type, length);

// Hier sollen type und length nun verändert sein

[...]

void get_info(type, length)
{
    type = 0x15;
    length = 0xFF;
}

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.

Autor: Gerd Gerd (gege)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das geht so:
unsigned char type, length;

get_info(&type, &length);


// Hier sollen type und length nun verändert sein

[...]

void get_info(unsigned char *type, unsigned char *length)
{
    *type = 0x15;
    *length = 0xFF;
}

Literaturhinweis:

"Programmieren in C", Brian Kernighan & Dennis Ritchie, Hanser-Verlag

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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).

struct type_length {
  unsigned char type;
  unsigned char length;
};


struct type_length get_info( struct type_length val )
{
  val.type = 0x15;
  val.length = 0xFF;
  return val;
}


unsigned char test( void )
{
  struct type_length x;

  x.type = 10;
  x.length = 11;
  x = get_info( x );
  return x.type + x.length;
}


Peter

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:

struct type_length get_info( struct type_length val )
{
  val.type = 0x15;
  val.length = 0xFF;
  return val;
}
  ce:   85 e1           ldi     r24, 0x15       ; 21
  d0:   9f ef           ldi     r25, 0xFF       ; 255
  d2:   08 95           ret

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:

void get_info1(unsigned char *type, unsigned char *length)
{
  ce:   fc 01           movw    r30, r24
  d0:   db 01           movw    r26, r22
    *type = 0x15;
  d2:   85 e1           ldi     r24, 0x15       ; 21
  d4:   80 83           st      Z, r24
    *length = 0xFF;
  d6:   8f ef           ldi     r24, 0xFF       ; 255
  d8:   8c 93           st      X, r24
}
  da:   08 95           ret



Peter

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: E.M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.