www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Variale Anzahl Werte auf Stack schreiben


Autor: Emax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

wie kann ich unter C eine variable Anzahl an Werten auf den Stack legen?

Ich habe ein Programms und binaris (Quellcode nur teilweise), dass 
bisher Hex-Werte als Steuerzeichen erhält. Dieser Quellcode soll orginal 
bleiben.
Ich muss eine Art Kommandointerpreter hinzufügen, der Befehle von einem 
Terminal erhält, diese auf den Stack schiebt und dann die Funktionen so 
aufruft, wie die Hex-Routine tut. Die Hex-routine selbst muss dabei 
erhalten bleiben. Je nach Schnittstelle (CAN oder RS232) wird entweder 
die Hex-Funktion verwendet, oder der Interpreter.
Ich habe mir verschiede Parser und Interpreter aus der Codesammlung 
angeschaut. Da sind die Funktionen so vorbereitet, dass die ihre Werte 
aus einen array aus unions lesen. Das kann ich nicht machen. Ich muss 
zur Laufzeit ermitteln, was ich wie auf den Stack schiebe und dann eine 
Funktion aufrufen.

Dazu muss ich je nach Befehl immer andere Daten auf den Stack schreiben, 
nur wie mach ich das in C? Ich kenne stdarg um eine variale Anzahl an 
Parametern vom Stack zu holen, wie heißen die Umkehrfunktionen dafür?

Emax

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die gibt es nicht.
Wenn es überhaupt geht, dann nur mit Assembler und/oder Schweinereien.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Separaten programmgesteuerten Stack dafür verwenden.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wenn es überhaupt geht, dann nur mit Assembler und/oder Schweinereien.

Z.B. malloc(). Igitt;)

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sollte das ganze nicht mit einer Variabel Parater liste wie bei printf 
gehen?

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das kommt darauf an, welcher ABI die jeweilige Compilerimplementierung 
folgt.

Der einzig sinnvolle Weg, eine nicht-ABI-konforme (Assembler)-Funktion 
mit den Parametern zu versorgen, die sie braucht, ist einen 
Assembler-Wrapper zu schreiben, die die Funktion so einpackt, daß sie 
ABI-konfirm ist und von Compiler-Ebene aus verwendbar wird.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ich mir hier als Schweinerei vorstellen könnte:

Man könnte sich die zu übergebenden Bereiche in einem
anderen Puffer zusammenbauen und den als eine Folge von z.B int
interpretieren.
Dann ruft man eine passende aus einem Satz von Funktionen auf,
die dann die nötige Anzahl Werte aus dem Puffer nimmt und als
Parameter an deine Endfunktion liefert.

Also etwa so:
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
//#include <string.h>
#include <stdint.h>
#include <stdarg.h>

void malmehrmalweniger( int anzahl, ... )
{
  int    i;

  va_list    val;
  va_start( val, anzahl );


  for( i=0; i<anzahl; ++i )
  {
    int   aktueller_wert = va_arg( val, int );
    printf( "%d 0x%08x\n", i, aktueller_wert );
  }
  va_end( val );
}

void ruf_malmehrmalweniger_auf_1( int wert1 )
{
  malmehrmalweniger( 1, wert1 );
}

void ruf_malmehrmalweniger_auf_2( int wert1, int wert2 )
{
  malmehrmalweniger( 2, wert1, wert2 );
}

void ruf_malmehrmalweniger_auf_3( int wert1, int wert2, int wert3 )
{
  malmehrmalweniger( 3, wert1, wert2, wert3 );
}

void ruf_malmehrmalweniger_auf_4( int wert1, int wert2, int wert3, int wert4 )
{
  malmehrmalweniger( 4, wert1, wert2, wert3, wert4 );
}

void ruf_malmehrmalweniger_auf( void *p, size_t n_bytes )
{
  switch( n_bytes )
  {
    case 1:
    case 2:
    case 3:
    case 4:
      ruf_malmehrmalweniger_auf_1( ((int*)p)[0] );
      break;

    case 5:
    case 6:
    case 7:
    case 8:
      ruf_malmehrmalweniger_auf_2( ((int*)p)[0], ((int*)p)[1] );
      break;

    case 9:
    case 10:
    case 11:
    case 12:
      ruf_malmehrmalweniger_auf_3( ((int*)p)[0], ((int*)p)[1], ((int*)p)[2] );
      break;

    case 13:
    case 14:
    case 15:
    case 16:
      ruf_malmehrmalweniger_auf_4( ((int*)p)[0], ((int*)p)[1], ((int*)p)[2], ((int*)p)[3] );
      break;

    default :

      break;
  }
}

int main( int nargs, char **args )
{
  // ausreichender Puffer für maximalen Stack:
  union
  {
    uint8_t     byte[0];
    int         i[4];
  } puffer;


  // Beispiel 1:
  // 3 Bytes zusammenbasteln
  printf( "Beispiel 1: 3 Bytes\n" );
  puffer.byte[0] = 0x12;
  puffer.byte[1] = 0x34;
  puffer.byte[2] = 0x56;
  ruf_malmehrmalweniger_auf( &puffer, 3 );

  // Beispiel 2:
  // 3 Bytes zusammenbasteln
  printf( "Beispiel 2: 8 Bytes\n" );
  puffer.byte[0] = 0x12;
  puffer.byte[1] = 0x34;
  puffer.byte[2] = 0x56;
  puffer.byte[3] = 0x78;
  puffer.byte[4] = 0x9a;
  puffer.byte[5] = 0xbc;
  puffer.byte[6] = 0xde;
  puffer.byte[7] = 0xf0;
  ruf_malmehrmalweniger_auf( &puffer, 8 );

  return 0;
}
malmehrmalweniger() soll deine Funktion sein, die du letztlich
aufrufen willst.

Ausgabe unter Linux:
klaus@vdr1:~ > gcc -Wall  -std=gnu99 t.c &&  ./a.out
Beispiel 1: 3 Bytes
0 0x08563412
Beispiel 2: 8 Bytes
0 0x78563412
1 0xf0debc9a

Voraussetzungen in diesem Beispiel:
- int werden auf dem aktuellen System direkt hintereinander übergeben
- die aufgerufene Funktion bekommt als erstes eine int, in der
  drin steht, wie viel Werte kommen (irgendwie muß sie ja
  erkennen, was da kommt)
- maximal 4 int in dieser Form
- man muß zusehen, daß die Felder reichen

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PS:
Die Ebene mit ruf_malmehrmalweniger_auf_1...4() kann man natürlich
auch weglassen und die Funktion direkt aus dem switch aufrufen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was auch eventuell geht:
Dazu muss aber der Argumentpassing Mechanismus vom C Compiler und das 
was die Assemblerfunktion auf dem Stack haben möchte, absolut kompatibel 
sein. Ist das nicht der Fall, kannst du das gleich alles wieder 
vergessen.

Schweinereien mit einem Funktionspointer.
Du definierst dir einen Haufen typedefs, die alle möglichen 
Aufrufargumentlisten abdecken.
Dann holst du dir die Adresse der Assemblerfunktion, castest den Pointer 
mit dem richtigen typedef zurecht und rufst die Funktion auf.

Im Prinzip ähnlich zu dem, was Klaus weiter oben gezeigt hat.

Aber ich fürchte das Problem wird einfach sein, dass die Assembler 
Funktion einen völlig anderen Argument Passing Mechanismus benutzt, als 
dein C Compiler. Ich schätze ohne eine Assembler Zwischenschicht wird 
das nichts werden.

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
holger schrieb:
>>Wenn es überhaupt geht, dann nur mit Assembler und/oder Schweinereien.
>
> Z.B. malloc(). Igitt;)

6, setzen! Wir reden hier über den Stack!

Autor: Emax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, ich danke euch sehr für die Antworten, Anregungen und Beispiele!
Ich werde es nach dem Vorschlag von  Klaus Wachtler realisieren, 
reserviere also eine Anzahl an char auf dem Stack und caste die dann 
irgendwie da drauf.

Gruß Emax

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.