ADTs in C

Hi Leute,
ich habe mal eine Frage zu abstrakten Datentypen in C.
Gegeben:
header.h:
typedef struct {int a;} T_str;
int getStrA(T_str str);
void setStrA(T_str * str, int a);

Problem: Ich habe einen Header mit einem struct und Zugriffsfunktionen. Das Struct muss im Header stehen, da ja benutzende Komponenten Variablen davon deklarieren müssen und diese den Zugriffsfunktionen mitgeben. Leider ist es bei der oben aufgezeichten Variante aber so, das die benutzenden Komponenten das struct auch selbst ändern können (z.B. str.a=3). Dies soll nicht möglich sein, da Änderungen nur über die zugriffsfkt. vorgenommen werden können (die dann z.B. vorher Nebenbedingungen prüfen u.ä.)
Ich hätte also gerne so was in der Art:
header.h:
typedef T_str;
int getStrA(T_str str);
void setStrA(T_str * str, int a);
imlp.c
typedef struct {int a;} T_str;

Also: Der Header sagt nur, es gibt einen Typen, die interne Struktur kennt aber nur die Implementierung. Ist so was in der Art in C möglich?

Ralph

P.S. Es geht mir nur um C, nicht C++

Hallo Ralph,

Also: Der Header sagt nur, es gibt einen Typen, die interne
Struktur kennt aber nur die Implementierung. Ist so was in der
Art in C möglich?

P.S. Es geht mir nur um C, nicht C++

Nein das geht nicht. Warum wohl wurde C++ entwickelt ??

  1. Die Variablen müssen ja vom aufrufenden Programm bereitgestellt werden, deshalb MUSS dieses die Struktur kennen, ansonsten hat der Compiler keine Ahnung wieviel Speicher er allozieren muss.

  2. Du kannst in C nur aufgerufenen Funktinen „verbieten“ eine Variable zu verändern. Entweder du übergibst der Wert by Value, also eine Kopie oder du deklarierst den Parameter als „const“.

  3. C ist halt etwas für erwachsene Programmierer, man muss nicht alles machen, was C erlebt.

Die einzige Möglichkeit wäre eine Funktion zu entwerfen, welche den Speicher alloziert und dann eine void* oder irgend eine char-array zurückliefert. Allerdings kannst du dann deine Bearbeitungsfunktionen mit jedem Scheiss aufrufen, was die Sicherheit auch nicht gerade verbessert.

MfG Peter(TOO)

Hallo Ralph,

das nennt man „forward reference“.

Alles was es in C++ gibt kann man auch in C schreiben (naja fast).

Ich hoffe folgendes Beispiel hilft dir.

Gruß
Stefan

******************
#include „malloc.h“

typedef struct _BUBU BUBU_STRUCT;

void InitBubu( _BUBU *Daten );

int main(int argc, char* argv[])
{
_BUBU *fdd=0;

InitBubu( fdd );
return 0;
}

typedef struct _BUBU {
int t;
} BUBU_STRUCT;

void InitBubu( _BUBU * Daten )
{
Daten = (_BUBU *)malloc(sizeof(_BUBU));
Daten->t = 10;
}

Hallo Stefan,

das nennt man „forward reference“.

C braucht immer die Größe des Objektes
(also aller enthaltenen Daten), um etwas
damit (mit dem Objekt selbst) machen zu können.
Wird eine struct ‚per value‘ übergeben, braucht
C die Datentypen, um Funktionsaufrufe generieren
zu können, da ja der Stack adjustiert werden muss.

Wenn nur (wie in Deinem Fall) ein Zeiger auf eine
Struktur „rumgereicht“ wird, kann der Compiler
immer „sizeof (*Zeigertyp)“ bestimmen und braucht
die innere Struktur nicht zu kennen.

Die Frage ist nun, ob dieses „Herumreichen“
vom Zeiger gewünscht war. Wenn nicht, geht
es in C demnach nicht.

Alles was es in C++ gibt kann man auch in C schreiben
(naja fast).

Aber das „fast“ gehört schon grossgeschrieben.
:wink:

Grüße

CMБ

Hallo Semjon!

das nennt man „forward reference“.

C braucht immer die Größe des Objektes
(also aller enthaltenen Daten), um etwas
damit (mit dem Objekt selbst) machen zu können.
Wird eine struct ‚per value‘ übergeben, braucht
C die Datentypen, um Funktionsaufrufe generieren
zu können, da ja der Stack adjustiert werden muss.

Der Orginalposter hatte aber danach gar nicht gefragt!
Außerdem wer Strukturen (geht datt überhaupt) per Value übergibt dem droht mindestens 3 Jahre Assembler als Strafe.

Wenn nur (wie in Deinem Fall) ein Zeiger auf eine
Struktur „rumgereicht“ wird, kann der Compiler
immer „sizeof (*Zeigertyp)“ bestimmen und braucht
die innere Struktur nicht zu kennen.

Das nennt man dann HANDLE überall und selbst in C++ noch sehr beliebt.

Alles was es in C++ gibt kann man auch in C schreiben
(naja fast).

Aber das „fast“ gehört schon grossgeschrieben.

Neee, ganz, ganz, ganz klein. Es gibt nichts was C++ kann und in C nicht hinschreibbar ist. Ob dies dann allerdings deinen esthetischen Ansprüchen noch genügt bleibt fraglich.

Gruß
Stefan

Tja Leute,
dass es in C++ und in C mit Zeigern geht, wusste ich selbst, aber leider kann man C++ nicht überall benutzen, wo man möchte. Aber danke trotzdem.

Ich werde versuchen ein erwachsener Programmierer zu werden :wink:

Ralph

P.S. Ein Struct per Value zu übergeben soll schlecht sein? Du meinst also, es wäre besser bei der Benutzung einer fremden Funktion erst mal Speicher zu reservieren, dann die Daten zu holen und dann wieder zu freizugeben, oder besser noch die erste Funktion malloct selbst und man muss nur noch freen. Willkommen im Land der Speicherlöcher. Wenn du mit mehreren (hundert) Leuten entwickelst, solltest du davon ausgehen, dass nicht jeder so gut malloct und freed wie du.

Ich werde versuchen ein erwachsener Programmierer zu werden
:wink:

Viel Erfolg!

P.S. Ein Struct per Value zu übergeben soll schlecht sein? Du
meinst also, es wäre besser bei der Benutzung einer fremden
Funktion erst mal Speicher zu reservieren, dann die Daten zu
holen und dann wieder zu freizugeben, oder besser noch die
erste Funktion malloct selbst und man muss nur noch freen.
Willkommen im Land der Speicherlöcher. Wenn du mit mehreren
(hundert) Leuten entwickelst, solltest du davon ausgehen, dass
nicht jeder so gut malloct und freed wie du.

Ja ein Struct per Value ist schlecht, es verbraucht Rechenzeit und die Größe des Stacks ist nicht mehr vorhersehbar (oder schwer). Wenn die rufende Funktion den Inhalt der Struct nicht kennen und verändern soll warum muß sie dann alle Member ständig kopieren???

Wenn die Programmierer nicht mal fopen, „mach und tu“, fclose hinschreiben können, ja dann hast du Speicherlöcher. Ein „Init“ und „Exit“ ist das gleiche wie ein malloc und free. Das hat nichts mit einem oder hundert Programmierern zu tun, sondern mit der Durchgängigkeit der Interfaces. Ich würde niemals etwas hinschreiben wo die rufende Funktion den Speicher freigeben muß, es gibt ein „Exit“.

Falls du allerdings darauf hinaus möchtest, das die Struct auf dem Stack angelegt wird und der Programmierer über ein free (exit) nicht nachdenken muß, da der return den Stack schon aufräumen wird, hast du wohl recht.
Diese Denke beschehrt uns gerade immer wieder neue Viren und Würmer (buffer overflow).
Ein Grund warum der Stack executable ist beschert uns C++, da es Klassen gibt in denen (intrinsic) Funktionen in der Klasse selbst implementiert sind und daher dann der Code auf dem Stack landet und dort ausgeführt wird.

Gruß
Stefan

Hi Stefan!

Ich werde versuchen ein erwachsener Programmierer zu werden
:wink:

Viel Erfolg!

Tja, das nächste mal mache ich [Ironie]-Tags drumrum, dann kapiert es jeder.

Ja ein Struct per Value ist schlecht, es verbraucht Rechenzeit
und die Größe des Stacks ist nicht mehr vorhersehbar (oder
schwer). Wenn die rufende Funktion den Inhalt der Struct nicht
kennen und verändern soll warum muß sie dann alle Member
ständig kopieren???

Ich will dich ja nicht aus deiner kleinen heilen PC-Welt holen, aber es gibt Systeme, da ist Speicher-allozieren aufwendiger als statische Objekte, und ein großes Problem ist der fragmentierte Speicher, weshalb, wenn möglich, statische Objekte genutzt werden sollten.

Wenn die Programmierer nicht mal fopen, „mach und tu“, fclose
hinschreiben können, ja dann hast du Speicherlöcher. Ein
„Init“ und „Exit“ ist das gleiche wie ein malloc und free. Das
hat nichts mit einem oder hundert Programmierern zu tun,
sondern mit der Durchgängigkeit der Interfaces. Ich würde
niemals etwas hinschreiben wo die rufende Funktion den
Speicher freigeben muß, es gibt ein „Exit“.

Auch da will ich dich nicht aus deiner heilen Welt holen, aber man kann sich leider seine Mitarbeiter nicht immer Aussuchen und es gibt genug Leute, die mal fopen, „mach und tu“, fclose nicht machen, aus welchen Gründen auch immer. Man muss leider oft genug mit der Dummheit anderer rechnen… (Aber was solls, dafür sind die in den asiatischen Ländern auch billiger, was interessiert, ob da viele Graupen bei sind…)

Falls du allerdings darauf hinaus möchtest, das die Struct auf
dem Stack angelegt wird und der Programmierer über ein free
(exit) nicht nachdenken muß, da der return den Stack schon
aufräumen wird, hast du wohl recht.
Diese Denke beschehrt uns gerade immer wieder neue Viren und
Würmer (buffer overflow).

Das tut mir leid für euch, ich habe für die Systeme, mit denen ich arbeite, noch keinen einzigen Wurm oder Virus gesehen…

Ein Grund warum der Stack executable ist beschert uns C++, da
es Klassen gibt in denen (intrinsic) Funktionen in der Klasse
selbst implementiert sind und daher dann der Code auf dem
Stack landet und dort ausgeführt wird.

Jaja, was so zwei kleine Plus ausmachen können :wink:

Es ist übrigens schön, wenn du einen Vortrag über die Schönheit und Unschönheit von statischer und dynamischer Allozierung hälst, leider war aber hier nicht danach gefragt. Es ist nämlich so, dass dieses Interface schon länger fest steht und somit die Variable nicht mehr in einen Zeiger geändert werden kann. Man kann nur noch Schaden begrenzen und dafür sorgen, dass die Leute keine Werte des Strukts selbst ändern, wenn sie nicht sollen. Da kann man noch so oft sagen, Zeiger wären besser, man darf es nicht mehr ändern.

So läuft es halt bei großer Softwareentwicklung…

Grüße

Ralph

P.S. Ich finde es schön, dass sich immer noch neue w-w-w-Rookies finden, noch viel Spaß im Forum und mögest du anderen Leuten mehr helfen als mir…

Ich werde versuchen ein erwachsener Programmierer zu werden
:wink:

Viel Erfolg!

Tja, das nächste mal mache ich [Ironie]-Tags drumrum, dann
kapiert es jeder.

Mal ganz ohne den Kontext zu kennen (oder überhaupt kennen zu wollen :stuck_out_tongue_winking_eye:) würde ich ein „Viel Erfolg“ nicht als allzu große Beleidigung auffassen. Wenn’s um C geht ist das viel Arbeit und mehr oder weniger Glückssache…

Auch da will ich dich nicht aus deiner heilen Welt holen, aber
man kann sich leider seine Mitarbeiter nicht immer Aussuchen
und es gibt genug Leute, die mal fopen, „mach und tu“, fclose
nicht machen, aus welchen Gründen auch immer.

Das ändert dann aber auch nichts daran, dass diese Leute in einem Job, in dem man C programmiert, nichts zu suchen haben. Vergessen tut man’s schonmal, man übersieht auch ab und zu mal ein kleines oder großes Leak, aber irgendwo sollte das dann Grenzen haben, die noch weit diesseits der Ignoranz liegen.

Das tut mir leid für euch, ich habe für die Systeme, mit denen
ich arbeite, noch keinen einzigen Wurm oder Virus gesehen…

Irgendwas seltenes im Embedded-Bereich? Fahrzeugelektronik? Ansonsten hätte ich keine Ideen mehr, wo es keine Viren oder Würmer gibt :wink:

So läuft es halt bei großer Softwareentwicklung…

Da läuft das dann aber normalerweise auch so, dass Konventionen befolgt werden, und wer sich nicht dran hält bekommt auf die Fresse. Das gilt ganz besonders in den Bereichen, in denen du dich rumzutreiben scheinst (durchaus nicht negativ gemeint). Wenn so eine Konvention besagt, dass gefälligst nur über irgendwelche Zugriffsfunktionen auf Datenfelder zugegriffen werden soll, dann muss das als Gesetz in Stein gemeißelt gelten, ansonsten kann man das Projekt gleich in die Tonne treten.

Hallo Nicos,

gib es auf.

Bei soviel Erfahrung in kleinen/mittel großen Projekten rennst du da gegen Wände. Solche Projekte gehen halt normalerweise in die Grütze und man lernt daraus (hoffentlich).

Das tut mir leid für euch, ich habe für die Systeme, mit denen
ich arbeite, noch keinen einzigen Wurm oder Virus gesehen…

Irgendwas seltenes im Embedded-Bereich? Fahrzeugelektronik?
Ansonsten hätte ich keine Ideen mehr, wo es keine Viren oder
Würmer gibt :wink:

Es gibt durchaus noch eine ganze Menge Bereiche in denen dieses zutrifft. Du hast aber völlig Recht das sind in der Regel Embedded-Systeme. Die Ignoranz bezüglich aktueller Probleme ist allerdings beeindruckend. Selbst im Automotive Bereich, Router und Set-Top-Box Bereich sind mittlerweile Viren oder Würmer bekannt. Es gibt kein System das nicht versucht wird zu kompromitieren wenn es nur eine einigermaßen Verbreitung hat. Soweit schaut man halt nicht über den Tellerrand (640kB RAM should be enough for everything).

Auch da will ich dich nicht aus deiner heilen Welt holen, aber
man kann sich leider seine Mitarbeiter nicht immer Aussuchen
und es gibt genug Leute, die mal fopen, „mach und tu“, fclose
nicht machen, aus welchen Gründen auch immer.

Das ändert dann aber auch nichts daran, dass diese Leute in
einem Job, in dem man C programmiert, nichts zu suchen haben.
Vergessen tut man’s schonmal, man übersieht auch ab und zu mal
ein kleines oder großes Leak, aber irgendwo sollte das dann
Grenzen haben, die noch weit diesseits der Ignoranz liegen.

Das Problem ist normalerweise, dass die Personalverantwortung wie auch die Projektverantwortung fehlt und dann nimmt man was man bekommen kann.

So läuft es halt bei großer Softwareentwicklung…

Da läuft das dann aber normalerweise auch so, dass
Konventionen befolgt werden, und wer sich nicht dran hält
bekommt auf die Fresse. Das gilt ganz besonders in den
Bereichen, in denen du dich rumzutreiben scheinst (durchaus
nicht negativ gemeint). Wenn so eine Konvention besagt, dass
gefälligst nur über irgendwelche Zugriffsfunktionen auf
Datenfelder zugegriffen werden soll, dann muss das als Gesetz
in Stein gemeißelt gelten, ansonsten kann man das Projekt
gleich in die Tonne treten.

Mal dahingestellt warum 100 oder 200 Entwickler als große Software Entwicklung bezeichnet werden, du hast vollkommen Recht. Es gibt klare Regeln an die man sich halten muß ansonsten „Auf Wiedersehen“ oder es gibt kein Geld (bei Subunternehmern). Auch hier wieder das Problem, die Projektleiter haben keinerlei Handlungsbefugnis und können daher nur versuchen das Beste daraus zu machen, leider oft ohne richtigen Erfolg.

Gruß
Stefan

Hallo Ralph!

P.S. Ich finde es schön, dass sich immer noch neue
w-w-w-Rookies finden, noch viel Spaß im Forum und mögest du
anderen Leuten mehr helfen als mir…

Ich bin zwar neu hier bei w-w-w aber warum beleidigst du mich deshalb?
Ist das ein Makel?
Hättest du deine Frage von Anfang an genauer gestellt, hättest du wohl auch Anworten bekommen die dir angemessener erscheinen.

Gruß
Stefan

Hallo Ralph,

Ich will dich ja nicht aus deiner kleinen heilen PC-Welt
holen, aber es gibt Systeme, da ist Speicher-allozieren
aufwendiger als statische Objekte, und ein großes Problem ist
der fragmentierte Speicher, weshalb, wenn möglich, statische
Objekte genutzt werden sollten.

Das Speicherallozieren (bei embedded) evil ist, lernt man sehr schnell nach dem Studium. Dass es Mittelwege gibt zwischen malloc und statisch, lernt man erst durch Erfahrung. Aber du hast natürlich recht, das ist alles of-topic, da dies nichts mit Deinem Ausgangsproblem zu tun hat. Die Lösung von Stefan ist natürlich bei statischer allozierung genauso anwendbar. Und natürlich kann der Inhalt des rumgereichten Zeigers übergeben werden, wenn per Konvention die Größe z.B. im ersten 2-byte Datenfeld steht, oder wenn statt des Zeigers ein Zeigerobjekt mit Zusatzatributen verwendet wird.

Für Deine Bastellösung (oder Schadensbegrenzung, wie Du es nennst), kannst Du z.B. in den header-Dateien von einer Basisklasse für Applikation und System 2 verschiedene Typen gleichen namens ableitest.

typedef struct
{

}s_base;

#if defined( SYSTEM )
typedef s s_base;
#elif defined (APPLIKATION)
typedef struct
{
unsigned char dummy[sizeof(s_base)]
}s;
#endif

#define s_base ((don’t use s_base))

Applikations-Programmierer könen so nichts mit Instanzen von s anfangen. Trotzdem bleiben Typprüfung und Größe gewahrt.

Gruß
achim