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
Die gibt es nicht. Wenn es überhaupt geht, dann nur mit Assembler und/oder Schweinereien.
>Wenn es überhaupt geht, dann nur mit Assembler und/oder Schweinereien.
Z.B. malloc(). Igitt;)
sollte das ganze nicht mit einer Variabel Parater liste wie bei printf gehen?
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.
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:
1 | #include <stdlib.h> |
2 | #include <stddef.h> |
3 | #include <stdio.h> |
4 | //#include <string.h>
|
5 | #include <stdint.h> |
6 | #include <stdarg.h> |
7 | |
8 | void malmehrmalweniger( int anzahl, ... ) |
9 | {
|
10 | int i; |
11 | |
12 | va_list val; |
13 | va_start( val, anzahl ); |
14 | |
15 | |
16 | for( i=0; i<anzahl; ++i ) |
17 | {
|
18 | int aktueller_wert = va_arg( val, int ); |
19 | printf( "%d 0x%08x\n", i, aktueller_wert ); |
20 | }
|
21 | va_end( val ); |
22 | }
|
23 | |
24 | void ruf_malmehrmalweniger_auf_1( int wert1 ) |
25 | {
|
26 | malmehrmalweniger( 1, wert1 ); |
27 | }
|
28 | |
29 | void ruf_malmehrmalweniger_auf_2( int wert1, int wert2 ) |
30 | {
|
31 | malmehrmalweniger( 2, wert1, wert2 ); |
32 | }
|
33 | |
34 | void ruf_malmehrmalweniger_auf_3( int wert1, int wert2, int wert3 ) |
35 | {
|
36 | malmehrmalweniger( 3, wert1, wert2, wert3 ); |
37 | }
|
38 | |
39 | void ruf_malmehrmalweniger_auf_4( int wert1, int wert2, int wert3, int wert4 ) |
40 | {
|
41 | malmehrmalweniger( 4, wert1, wert2, wert3, wert4 ); |
42 | }
|
43 | |
44 | void ruf_malmehrmalweniger_auf( void *p, size_t n_bytes ) |
45 | {
|
46 | switch( n_bytes ) |
47 | {
|
48 | case 1: |
49 | case 2: |
50 | case 3: |
51 | case 4: |
52 | ruf_malmehrmalweniger_auf_1( ((int*)p)[0] ); |
53 | break; |
54 | |
55 | case 5: |
56 | case 6: |
57 | case 7: |
58 | case 8: |
59 | ruf_malmehrmalweniger_auf_2( ((int*)p)[0], ((int*)p)[1] ); |
60 | break; |
61 | |
62 | case 9: |
63 | case 10: |
64 | case 11: |
65 | case 12: |
66 | ruf_malmehrmalweniger_auf_3( ((int*)p)[0], ((int*)p)[1], ((int*)p)[2] ); |
67 | break; |
68 | |
69 | case 13: |
70 | case 14: |
71 | case 15: |
72 | case 16: |
73 | ruf_malmehrmalweniger_auf_4( ((int*)p)[0], ((int*)p)[1], ((int*)p)[2], ((int*)p)[3] ); |
74 | break; |
75 | |
76 | default : |
77 | |
78 | break; |
79 | }
|
80 | }
|
81 | |
82 | int main( int nargs, char **args ) |
83 | {
|
84 | // ausreichender Puffer für maximalen Stack:
|
85 | union
|
86 | {
|
87 | uint8_t byte[0]; |
88 | int i[4]; |
89 | } puffer; |
90 | |
91 | |
92 | // Beispiel 1:
|
93 | // 3 Bytes zusammenbasteln
|
94 | printf( "Beispiel 1: 3 Bytes\n" ); |
95 | puffer.byte[0] = 0x12; |
96 | puffer.byte[1] = 0x34; |
97 | puffer.byte[2] = 0x56; |
98 | ruf_malmehrmalweniger_auf( &puffer, 3 ); |
99 | |
100 | // Beispiel 2:
|
101 | // 3 Bytes zusammenbasteln
|
102 | printf( "Beispiel 2: 8 Bytes\n" ); |
103 | puffer.byte[0] = 0x12; |
104 | puffer.byte[1] = 0x34; |
105 | puffer.byte[2] = 0x56; |
106 | puffer.byte[3] = 0x78; |
107 | puffer.byte[4] = 0x9a; |
108 | puffer.byte[5] = 0xbc; |
109 | puffer.byte[6] = 0xde; |
110 | puffer.byte[7] = 0xf0; |
111 | ruf_malmehrmalweniger_auf( &puffer, 8 ); |
112 | |
113 | return 0; |
114 | }
|
malmehrmalweniger() soll deine Funktion sein, die du letztlich aufrufen willst. Ausgabe unter Linux:
1 | klaus@vdr1:~ > gcc -Wall -std=gnu99 t.c && ./a.out |
2 | Beispiel 1: 3 Bytes |
3 | 0 0x08563412 |
4 | Beispiel 2: 8 Bytes |
5 | 0 0x78563412 |
6 | 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
PS: Die Ebene mit ruf_malmehrmalweniger_auf_1...4() kann man natürlich auch weglassen und die Funktion direkt aus dem switch aufrufen.
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.
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!
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
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.