Hallo,
ich brauchs für ein Mikrocontroller, aber prizipiell ists ja ne
allgemeine C-Frage.
Code:
1
#define Buffer_Size = 64
2
3
structFIFO
4
{
5
uint8_tdata[Buffer_Size];
6
uint8_tread;
7
uint8_twrite;
8
}
9
10
structFIFOFIFO_Buffer[2]
Ich habe also einen FIFO Buffer erzeugt. Er funktioniert mit dem Code
drumrum...
Mein Problem:
- ich fänds gut wenn ich meinen Code zum schreiben und lesen nicht für
meine 2. Variante ändern muss.
- Ich möchte das mein erzeugtes Array im struct Object verschiedene
Größen haben kann. Also z.B. FIFO_Buffer[0] hat ein array der größe 32;
FIFO_Buffer[1] ein Array der größe 64.
Ist das machbar, oder muss ich ein neues struct erzugen und für dieses
dann den Code neu schreiben/anpassen?
Lg
Du ersetzt in der Struktur data durch einen Zeiger auf einen Puffer.
Dieser Puffer wird dann woanders (statisch oder dynamisch) definiert,
der Zeiger wird mit der Startadresse des Puffers initialisiert.
Zusätzlich erweiterst du die Struktur um ein Element buffer_size.
Es ist nicht nur eine C Frage. Es kommt auch auf den µC an.
Was du bräuchtest ist eine dynamische Speicherverwaltung. Desktop-PC´s,
Laptops, ähnlich mächtige Systeme haben das oder Betriebsystemverwaltete
µC´ler KÖNNEN das haben.
Die kleinen 8Bitter die ich kenne, können keinen Speicher dynamisch
allokieren - mag sein, dass es welche gibt die das können.
Sonst kenne ich vom Anwenden her noch die stm32, die können dynamisch
allokieren und auch freigeben - ABER wenn man es zu oft macht zerlöchert
man sich den Heap (Sidekick zu den betriebsverwalteten Systemen, von
denen manche aufräumen können, kenne mich jedoch nicht weiter aus).
Ich bin nich ganz sicher ob ichs verstanden hab..
Meinst du das so??
Und den Pointer auf ein Array oder einen Ringpuffer? .. also n puffer
erstellen um meinen puffer drauf zeigen zu lassen??
1
#define Buffer_Size = 64
2
3
structFIFO
4
{
5
int*data_ptr=&....
6
uint8_tBuffer_Size;
7
uint8_tread;
8
uint8_twrite;
9
}
10
11
structFIFOFIFO_Buffer[2]
Ich glaub ich versteh nich alles. Es wäre cool wenn dus mirs noch anders
erklären/zeigen(z.B. mit code) könntest.
FYI
Atmega 2560 , mittels AVR-Studio5
Wuhu W. schrieb:> Meinst du das so??
Fast.
> Es wäre cool wenn dus mirs noch anders erklären/zeigen(z.B. mit code)> könntest.
So könnte bspw. der Code aussehen (mit statischen Puffern, falls du
keine dynamischen Speichert verwenden möchtest):
1
#include<stdint.h>
2
3
// FIFO-Datenstruktur für beliebige Puffergrößen
4
5
structFIFO
6
{
7
uint8_t*data_ptr;
8
uint8_tbuffer_size;
9
uint8_tread;
10
uint8_twrite;
11
};
12
13
// Verschieden große Puffer für drei FIFOs
14
15
uint8_tbuffer0[32];
16
uint8_tbuffer1[64];
17
uint8_tbuffer2[16];
18
19
// Array von drei FIFOs mit Initialisierung der Puffer
20
21
structFIFOFIFO_Buffer[3]=
22
{
23
{buffer0,sizeofbuffer0,0,0},
24
{buffer1,sizeofbuffer1,0,0},
25
{buffer2,sizeofbuffer2,0,0}
26
};
Den Funktionen zum Schreiben und Lesen der FIFOs wird jeweils ein Zeiger
(z.B. fifo_ptr) auf die FIFO-Datenstruktur übergeben. Innerhalb dieser
Funktionen greift du auf den Puffer mit fifo_ptr->data_ptr[i] zu. Beim
Hochzählen der read- und write-Indizes werden diese jeweils beim
Erreichen von fifo_ptr->buffer_Size auf 0 zurückgsetzt. Alles in Allem
sind an diesen Funktionen wahrscheinlich nur geringfügige Änderungen
notwendig.
read und write sind hier Member Functions innerhalb derer Du auf
BufferSize wie auf eine Konstante zugreifen kannst. Noch eleganter
wäre es natürlich, wenn man auch gleich noch den gespeicherten Typ zum
Parameter macht (und für die Indizes würde ich Pointer verwenden, auch
wenn Du lieber bei C bleiben solltest):
Vielen Dank!
Funktioniert Perfekt.
Musste die Zuweisungen meines Objects
1
structFIFOFIFO_Buffer[4]=
2
{
3
{...},
4
{...}
5
};
lediglich in .c file machen, gab sonst compilier Fehler.
Wie kann ich meine Objecte der Struktur FIFO in einem .h file
deklarieren, wenn sie in .c initialisiert werden?
weil wenn ich ja jetzt schreibe
Wuhu W. schrieb:> weil wenn ich ja jetzt schreibe>> struct FIFO FIFO_Buffer[4];> Dann wird ja>> wieder ein Object erstellt oder?
Im Header-File musst du die Variablen als "extern" deklarieren:
A. H. schrieb:> Genau dafür wurden in C++ die Templates erfunden:
Wirklich?
Wird da nicht für jede Instanz des Templates(Oder wie ist der
Fachausdruck für ein instanziiertes Template?) Code erzeugt?
Josef schrieb:> A. H. schrieb:>> Genau dafür wurden in C++ die Templates erfunden:>> Wirklich?>> Wird da nicht für jede Instanz des Templates(Oder wie ist der> Fachausdruck für ein instanziiertes Template?) Code erzeugt?
Ja.
Aber der springende Punkt ist, dass du den Code nicht selber schreiben,
respektive mit anderen Zahlenwerten duplizieren, musst.
Letzten Endes gibt es nur 2 Möglichkeiten:
entweder man dupliziert oder man gestaltet es so, dass der dynamische
Teil nicht Teil der Struktur ist. Will man Elemente in einem Array
zusammenfassen, dann müssen alle Elemente die gleiche Größe haben. Da
führt kein Weg daran vorbei.
Karl Heinz schrieb:> Letzten Endes gibt es nur 2 Möglichkeiten:> entweder man dupliziert oder man gestaltet es so, dass der dynamische> Teil nicht Teil der Struktur ist. Will man Elemente in einem Array> zusammenfassen, dann müssen alle Elemente die gleiche Größe haben. Da> führt kein Weg daran vorbei.
Schon klar.
Was ich bemängelt habe war dass Templates für diesen Zweck gedacht sind.
Für jede im Projekt verwendete Puffergröße extra Code zu generieren
(egal ob mir das der Compiler abnimmt) ist auf einem Mikrocontroller
wohl nicht der beste Weg (wobei "beste" zu definieren wäre).
Josef schrieb:> Was ich bemängelt habe war dass Templates für diesen Zweck gedacht sind.> Für jede im Projekt verwendete Puffergröße extra Code zu generieren> (egal ob mir das der Compiler abnimmt) ist auf einem Mikrocontroller> wohl nicht der beste Weg (wobei "beste" zu definieren wäre).
Einverstanden, eine Aussage wie: auch dafür wurden Templates einst
erfunden wäre sicherlich richtiger gewesen, schon deshalb, weil Typen
als Template-Parameter damals eine mindestens ebenso große Rolle
gespielt haben dürften wie numerische.
Das Templates zwangsläufig zu schlechterem Code führen müssen – wobei
ich „schlechter“ hier mal als gleichbedeutend mit „länger“ verstehe –
würde ich so aber nicht unterschreiben. Denn durch das Einbringen von
zusätzlichen Informationen ins das Typsystem eröffnen sich dem Compiler
ja auch neue Optimierungsmöglichkeiten. Welcher Effekt hier stärker zum
Tragen kommt hängt natürlich vom Einzelfall ab, hier konkret von der
Anzahl der verschiedenen Puffergrößen. Sollten dass nur zwei oder drei
sein, wobei auf jeden Puffer vielleicht nur an einer Stelle geschrieben
und an nur einer anderen gelesen wird, eine inline-Funktion also ohnehin
die bessere Variante wäre, dann könnte ich mir durchaus vorstellen, dass
die Template-Version sogar den kürzeren Code liefert, zumindest aber
keinen unakzeptabel längeren. Sie kann dann die Puffergröße als
Konstante in den Code compilieren, statt auf eine Variable zugreifen zu
müssen. Natürlich wird sie mit zunehmender Anzahl an Puffergrößen immer
schlechter abschneiden.
Ich hatte vor einigen Jahren mal ein Projekt mit einem nicht
unerheblichen Anteil an Grafikprogrammierung. Dafür war ich auf der
Suche nach einer Vektor-Klasse mit einer festen Anzahl Komponenten. Die
kann man grundsätzlich entweder als Array mit Schleifen oder als
Struktur bzw. in diesem Fall als rekursives Template mit entsprechend
generierten Anweisungssequenzen implementieren. Natürlich machen
Schleifen bei Vektoren für zwei- oder dreidimensionale Räume wenig Sinn
und so verwundert es nicht, dass die Template-Variante trotz mehrfacher
Anweisungen fast immer kürzeren Code geriert hat. (Allerdings kann es
sein, dass ein guter Compiler kurze Schleifen auch heraus optimiert und
durch Sequenzen ersetzt.) Erst ab vier Dimensionen zeigten sich messbare
Unterschiede in der Codegröße. Bezüglich der Laufzeit war die
Template-Variante natürlich in jedem Fall überlegen.
Es gibt übrigens auch Techniken, Stichwort: partielle Spezialisierung,
mit denen kann man z.B. für Vektoren festlegen, dass ein-, zwei- und
dreidimensionale sequenziell, alle anderen iterativ implementiert
werden. Die iterative Variante lässt sich dann auch als generische
Version implementieren. Der für die jeweilige Spezialisierung
generierter Code ist dann nur noch ein inline Wrapper, der die
generische Funktion typsicher mit den richtigen Parametern aufruft. Das
dürfte dann auch auf einem μC keine Wünsche mehr offen lassen.