mikrocontroller.net

Forum: Compiler & IDEs Peinliche Frage zu C-Grundlagen


Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo alle zusammen!

Habe eine etwas peinliche Frage zu C.
Habe programmieren mit C# gelernt. Da kann ich eine Klasse mit meinen 
Methoden definieren und diese beliebig oft initiieren.
Wenn ich also eine Klasse MyBuffer habe, mit den Mehtoden Add, Read, 
Remove, ... und diese als TX und RX brauche, dann lege ich einmal
MyBuffer rx = new MyBuffer();
und
MyBuffer tx = new MyBuffer();
 an.
Zugreifen kann ich dann z.B. mit
rx.Add(rx_byte)

Wie mache ich das jetzt in C, wenn ich einen TX und einen RX Buffer habe 
und ein C-File mit meinen Methoden?!?

Danke für die Hilfe.

Gruß
Lars

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich nehme an dass du wirklich C meinst und nicht C++

die Daten musst du als struct anlegen, die Methoden als Funktionen denen 
du eine  Zeiger auf diese structs übergibst

Autor: mano_wee (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ringpuffer könnte das sein was Du sucht: FIFO

Autor: MaWin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ich also eine Klasse MyBuffer habe,
> mit den Mehtoden Add, Read, Remove

> Wie mache ich das jetzt in C

Na ja, wenn du in C eine Implementation eines
MyBuffer hast, mit add, read, remove,
dann machst du das praktisch genau so.

MyBuffer rx = newbuffer();
add(rx,rx_byte);

Aber du hast so eine Implementation nicht :-)

Du musst es halt so machen, wie es in deiner
Umgebung möglich ist, und falls du (weil es
ein mickriger uC ist) keine brauchbare
Implementaion eines MyBuffer findest,
musst du ihn dir selber schreiben.

#define BUFSIZ 512
char buffer[BUFSIZ];
int inpos=0;
int outpos=0;
void add(char ch) { buffer[inpos=(inpos+1)%BUFSIZ]; }
char read(void) { return buffer[outpos=(outpos+1)%BUFSIZ]; }
int full(void) { return (inpos+1)%BUFSIZ==outpos; }
int empty(void) { return inpos==outpos; }

Das täte aich vielen C+ Programmen gut, dann würden sie nicht
so viel Ballast durch eierlegende Wollmilchsäure rumtragen.

Allerdings wäre es dann anders als meinen obiger Code
wenigstens getestet :-)

Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ok, jetzt stehe ich nur noch mit einem Bein auf dem Schlauch.

Wenn ich jetzt also einen RX und TX Buffer brauche muss ich den Code 
wirklich zweimal machen und in ein eigenes C File speichern. Bzw. zwei 
Puffer anlegen und den Methoden irgendwie den richtigen Puffer 
übergeben!?

Gruß
Lars

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Walter schrieb:
> die Daten musst du als struct anlegen, die Methoden als Funktionen denen
> du einen Zeiger auf diese structs übergibst

Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, mein ich doch!

Ich habe mein C-File mit den Funktion Add, Read, ....
Die Funktionen haben als Übergabeparameter z.B.
void Add(Buffer* buffer, char value)
Dann ein h-File, indem mein Puffer-Struct definiert und mit
extern
 auf meine Funktionen verwiesen ist.
Das h-File füge ich dann bei den c-Files ein, wo ich es brauche.
Lege dann dort meine Puffer mit der Struct an
Buffer rx = new Buffer();
 und wenn ich dann ein Byte hinzufügen will mache ich
Add(&rx, <wert>);
!?

Gruß
Lars

Autor: 900ss D. (900ss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab MaWins Code mal modifiziert: ist auch ungetestet :-)
#define BUFSIZ 512
typedef struct buff_s
{
  char buffer[BUFSIZ];
  int inpos=0;
  int outpos=0;
} buff_t;

// 3 Instanzen von buff_t (Daten)
buff_t buffer1, buffer2, buffer3;

// hier die Functionen
void add(buff_t *b, char ch) { b->buffer[b->inpos=(b->inpos+1)%BUFSIZ]; }
char read(buff_t *b) { return b->buffer[b->outpos=(b->outpos+1)%BUFSIZ]; }
int full(buff_t *b) { return (b->inpos+1)%BUFSIZ==b->outpos; }
int empty(buff_t *b) { return b->inpos==b->outpos; }

// Aufruf für einen Instanz z.B.:

add( &buffer1, 'a' );


Edit: ah du hast es ja scheinbar auch schon selber so ähnlich gemacht.

Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wo definiere ich jetzt am Besten was!?

Wenn ich zwei C-Files habe, indem die zwei Schnittstellen abgehandelt 
werden (Daten in RX-Puffer schreiben, TX-Puffer lesen), entsprechend 
zwei C-File, indem die jeweiligen Daten analysiert werden (Daten aus dem 
RX-Puffer lesen, TX-Puffer schreiben),  und ein C-File für den Buffer 
mit meinen Add-, Read- ... Funktionen!?

Denn es müssen sich ja immer einmal die Schnittstelle + Datenanalyse den 
gleichen Puffer verwenden.

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

Bewertung
0 lesenswert
nicht lesenswert
Lars schrieb:
> Und wo definiere ich jetzt am Besten was!?

Du hast es immer noch nicht.

Da du schreibst, dass du in Objektorientierter Programmierung firm bist:

Das hier

buff_t buffer1, buffer2, buffer3;

sind 3 'Objekte' vom Typ buff_t

Das hier
void add(buff_t *b, char ch) { b->buffer[b->inpos=(b->inpos+1)%BUFSIZ]; 
}
char read(buff_t *b) { return b->buffer[b->outpos=(b->outpos+1)%BUFSIZ]; 
}
int full(buff_t *b) { return (b->inpos+1)%BUFSIZ==b->outpos; }
int empty(buff_t *b) { return b->inpos==b->outpos; }

sind die 'Member-Funktionen' der 'Klasse'

Wenn du eine 'Member-Funktion' aufrufst, dann gibst du der Funktion 
einen Pointer auf 'das Objekt' mit, damit die 'Member-Funktion' auf 
diesem Objekt operieren kann.

> Wenn ich zwei C-Files habe, indem die zwei Schnittstellen abgehandelt
> werden (Daten in RX-Puffer schreiben, TX-Puffer lesen), entsprechend
> zwei C-File, indem die jeweiligen Daten analysiert werden (Daten aus dem
> RX-Puffer lesen, TX-Puffer schreiben),  und ein C-File für den Buffer
> mit meinen Add-, Read- ... Funktionen!?

Das kommt jetzt auf den genauen Aufbau an (ISR, nicht ISR).

Aber du kannst zb die beiden Buffer als globale Variablen machen und die 
einzelnen Funktionen (Schnittstelle + Datenanalyse) greifen auf den 
jeweils richtigen Buffer zu und benutzen die Funktionen aus der 
Buffer-Lib zur Manipulation der Buffer.

Übertreib aber nicht. Aufteilen von Funktionalitäten in Files nach 
Themenkreisen geordnet ist zwar gut. Wenn man es aber zu weit treibt, 
wird es nur unübersichtlich.
zb kann man eventuell Schnittstellencode + einen Teil der Datenanalyse 
durchaus in ein File zusammenfassen, dessen Aufgabe es ist irgendwelche 
"Datensätze" von einer Schnittstelle zu holen. "Datensätze' ist schon 
ein etwas höheres Konzept als einfach nur ein Bytestrom, wie er von der 
Schnittstelle kommt.
Die ganze Bufferverwaltung, die dazu notwendig ist, findet sich dann nur 
in dieser 1 Datei.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Will man die FIFO mit den Interrupts verwenden, kommen noch verschiedene 
Probleme hinzu (Interruptfreigabe, volatile, Atomizität).

Hier ein fertiges Beispiel, was all dies beachtet:

Beitrag "AVR-GCC: UART mit FIFO"


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.