Forum: Compiler & IDEs Vererbung in C? (allgemein, nicht nur GCC)


von Be B. (bebo)


Lesenswert?

Hallo,

gibt es einen offiziellen Weg folgendes in C zu realisieren?

Ich habe mehrere Hardwarekomponenten (UART, USB, ...).

Alle können Datenströme senden und empfangen. D.h. für jede 
Hardwarekomponente gibt es ein struct, welches die Komponente verwaltet.
Nun haben diese structs gemeinsamme Elemente. Z.B. verfügt jede 
Hardwarekomponente über einen Send- und Empfangspuffer + dazugehörige 
Pointer. Diese sind für alle Hardwarekomponentet/structs gleich.

Nun möchte ich eine C-Funktion schreiben, der ich jede dieser 
verschiedenen structs übergeben kann.
Wichtig wäre da aber, daß z.B. der RxBuffer in allenen structs den 
gleichen Offset hat.

In C++ würde man da ja z.B. eine struct/class entwerfen, die dieses 
gemeinsammen Elemente enthält. Alle speziellen structs/classes würden 
dann von dieser erben.
Somit könnte man der Funktion einen Pointer vom Typ Basisklasse 
übergeben und man kann sicher sein, daß die in der Basisklasse 
deklarieretn Elemente für alle Hardwarekomponenten an der gleichen 
stelle liegt.

Wie macht man das in C?

von der mechatroniker (Gast)


Lesenswert?

Eklige Variante: cast

Bessere Variante: die gemeinsamen Komponenten in einer Unter-Struct 
zusammenfassen, von der dann eine Instanz in jeder Haupt-Struct ist. Der 
Programmteil, der keine Unterscheidungen macht, bekommt dann einen 
Zeiger auf diese Unter-struct.

von Be B. (bebo)


Lesenswert?

Habe ich mir schon gedacht. Ich hatte aber gehofft, daß ich die doppelte 
Indirektion umgehen kann.

Kann man ich eigentlich darauf verlassen, daß die oberen struct-Member 
in verschiedenen structs, wenn sie gleich sind, immer den gleichen 
Offset haben?

von chris (Gast)


Lesenswert?

Du definierst ein Struct, als CPP define z.B. und verwendest es.
Nicht elegant, aber portable.

#define HW_CLASS \
 int size; \
 int used;
 char* head; \
 char* foot; \
 char buff[0]

Wenn der/die Compiler alle unnamed structures unterstützt, dann 
definiere
eine Struct, und instanziere es, das ist sauberer, aber nicht portabel.

von Be B. (bebo)


Lesenswert?

@chris:
Was meinst Du mit "als CPP define"?
Und was meinst Du mit "sauber, aber nicht portabel"? Solange es die 
Compiler unterstützen und ich den Datenblock nicht blind auf ein anderes 
System übertrage, sollte es doch gehen, oder?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Die einzelnen IO-Typen (oder Zeiger darauf) in eine Union stopfen?
1
#include "usb.h"
2
#include "uart.h"
3
#include "i2c.h"
4
...
5
6
enum
7
{
8
    IO_USB,
9
    IO_UART,
10
    IO_I2C,
11
    ...
12
13
    IO_NIL
14
};
15
16
typedef union
17
{
18
    int id;
19
20
    struct
21
    {
22
        int id;
23
        usb_t data;
24
    } usb;
25
26
    struct
27
    {
28
        int id;
29
        uart_t data;
30
    } uart;
31
32
    ...
33
34
} io_t;
35
36
void handle_io (io_t * io)
37
{
38
    switch (io->id)
39
    {
40
        case IO_USB:
41
            io->usb.data.buffer[0] = '0';
42
            break;
43
44
        case IO_UART:
45
            io->uart.data.buffer[0] = '0';
46
            break;
47
48
        ...
49
50
        default:
51
            fatal_error();
52
            break;
53
    }
54
}

Das ist keine Verebung, aber es gibt dir verschiedene Sichten auf dein 
io-Objekt. Und in uart.h:
1
#include "buffer.h" // extern char buf[];
2
3
typedef struct
4
{
5
    ...
6
    char * buffer;
7
    ...
8
} uart_t;
9
10
void uart_init (uart_t * uart)
11
{
12
    uart->buffer = buf;
13
    ...
14
}

von chris (Gast)


Lesenswert?

>Was meinst Du mit "als CPP define"?
einfach eine preprozessor define, habe dir ein Beispiel dort gemacht.
struct hw_serial { HW_CLASS; char dummy[100]; } hw_serial1,hw_serial2;

>Und was meinst Du mit "sauber, aber nicht portabel"? Solange es die
>Compiler unterstützen und ich den Datenblock nicht blind auf ein anderes
>System übertrage, sollte es doch gehen, oder?

Ja, wenn es deine Compiler unterstützen.

Z.B.

struct hw_base { int size; char *head; char*tail; ... };

struct hw_rs232 { struct hw_base; int port; ... } serial1, serial2;

dann kannst du im Code z.B.  serial1.size usw benutzen, als hättest du
sie in hw_rs232 declariert.

Bei neueren Branches des GCC kann es sein, daß du -fms-extensions als
Kommandozeile übergeben mußt, damit er das macht, früher konnter es es 
auch
ohne.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Johann L. schrieb:

> Das ist keine Vererbung, aber es gibt dir verschiedene Sichten auf dein
> io-Objekt. Und in uart.h:

.uart.data.buffer und .usb.data.buffer liegen nicht notwendig an der 
gleichen Adresse (was auch nicht nötig ist) aber sie zeigen auf die 
gleiche Adresse, wenn diese Zeiger richtig initialisiert wurden (siehe 
unten). Beachte, daß das dann nicht reentrant-fähig ist.

von Be Bo (Gast)


Lesenswert?

So, so,..

... und da sag noch einer, für Microcontroller brauche man kein C++. 
Dabei könnte das Leben doch so einfach sein.

Dann fang ich mal an mir eine Lösung zu stricken ;-)

von chris (Gast)


Lesenswert?

Was hindert dich daran, den mikrocontroller in c++ zu programmieren ?

von chris (Gast)


Lesenswert?

Auch ich habe schon Pic uC in C++ programmiert, und der ist bei
weitem limitierter als AVR.

von der mechatroniker (Gast)


Lesenswert?

> Habe ich mir schon gedacht. Ich hatte aber gehofft, daß ich die doppelte
> Indirektion umgehen kann.

Ein CPP-Compiler macht bei Vererbung nix anderes.
Aus
1
class Dings : public class Bums {
2
   int some_field;
3
};
4
5
...
6
Dings d;
7
Bums *b = &d;

wird
1
struct Dings {
2
   struct Bums _base;
3
   int some_field;
4
};
5
6
...
7
struct Dings d;
8
struct Bums *b = &(d._base);

Da bei Einfachvererbung das Basisobjekt an den Anfang des Gesamt-Structs 
gepackt wird, ist diese Indirektion übrigens im Maschinencode recht 
trivial ;-)

Und, wie schon von den Vorpostern genannt: Nimm nen C++-Compiler. Du 
musst ja außerhalb dieser Stelle keine C++-Features nutzen, von daher 
hat dies auf die Codegröße keine negativen Auswirkungen.

von Be B. (bebo)


Lesenswert?

Gibt es denn einen C++ Compiler für die PIC32? Der C32 can kein C++ :-(

von gast (Gast)


Lesenswert?

pic32 sowie pic18 Compiler ist GCC (Gnu C Compiler), man bekommt auch 
die Sourcen. Klar kann der C++. Bei pic24 sowie pic3x weiß ich nicht, ob 
das
GCC ist, oder nicht. Warscheinlich.

von Michael H. (morph1)


Lesenswert?

der gcc ist ein c compiler
der g++ ist ein c++ compiler

der c18 ist KEIN gcc, der pic24 aka c30 ist ein gcc derivat

die anderen angaben stimmen

irgendwie verwaschen das thema, auf jedenfall ist der c18, c30 und c32 
KEIN C++ compiler

von chris (Gast)


Lesenswert?

Hier ein Thread mit Beispielprogramm am Schluss über das 
objektorientierte Programmieren in C:

Beitrag "Objekte in C"

von Rolf Magnus (Gast)


Lesenswert?

> der gcc ist ein c compiler
> der g++ ist ein c++ compiler

und die GCC ist alles zusammen (Gnu Compiler Collection)

von morph1 (Gast)


Lesenswert?

na dann anders ausgedrückt, die gcc die microchip liefert kann kein c++ 
:)

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
Noch kein Account? Hier anmelden.