Forum: Compiler & IDEs 2 kleine Fragen zu C (GCC)


von Daniel (Gast)


Lesenswert?

hallo. ich habe in einem C-Programm folgende zeilen entdeckt:

class CMessage;
class CMsgs;

die klassen werden später in einer anderen datein definiert.
Was bewirken die "vordefinition" der klassen überhaupt ?

Dann hab ich noch eine frage zu IMPORT_C und EXPORT_C.
ich habe eine funktion die folgendermaßen definiert ist:

IMPORT_C void Internalize( ... );

was bewirkt das IMPORT_C ? und wo kommt überhaupt EXPORT_C zum einsatz
(EXPORT_C ist mir zufällig mal über den weg gelaufen)

Danke.
MfG

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Das Schlüsselwort "class" gibt es in C nicht; entweder handelt es sich
um C++ oder das ist irgendwo als Makro/Typ definiert. Das gleiche gilt
für IMPORT_C/EXPORT_C.

von Chris (Gast)


Lesenswert?

IMPORT_C/EXPORT_C ist, soweit ich weiß, weder im C noch im C++-Standard
definiert. Um die Bedeutung zu erfahren, musst du also wenigstens den
verwendeten Compiler und die verwendeten Bibliotheken angeben (oder
einfach selbst in der Doku nachschauen, da steht es bestimmt).

Hat deine Beispiel-Funktion Internalize wirklich drei Punkte als
Parameter? Du solltest bedenken, dass ... in Parameterlisten eine
spezielle Bedeutung hat und als Platzhalter in Beispielen in den
meisten Fällen ungeeignet ist.



Zur "Vordefinition" der Klasse:
Die heißt wirklich so, normal nimmt man aber die englische Bezeichnung
"forward-declaration" (zumindest hab ich die deutsche eher selten
gehört).

Wie der Name schon sagt, wird dabei eine Klasse vorwärts deklariert.
Die Deklaration sagt dem Compiler: "Es gibt eine Klasse mit dem Namen
soundso", mehr nicht.
Man kann im folgenden daher Zeiger und Referenzen auf diese noch nicht
Klasse erzeugen. Man kann die Zeiger und Referenzen nur noch nicht
benutzen, weil der Compiler die Klasse eben noch nicht wirklich kennt.
Ebensowenig kann man Instanzen erstellen.

Man benutzt solche Deklarationen zum Beispiel dafür:
class B;
class A {
  B* p;
};
class B {
  A* p;
};

Ohne forward-declaration von B wäre obiger Code nicht kompilierbar, da
der Compiler immer eine der beiden Klassen zuerst sieht und zu dem
Zeitpunkt die andere noch nicht kennt.

von Daniel (Düsentrieb) (Gast)


Lesenswert?

@Chris: Dann hab ich ja gut geraten ;) Ich verstehe zwar nicht den sinn
von deinem beispiel aber die funktionsweise ist mir klar geworden.
woher weisst du das mit den forward-declarations ? in meinen c / c++
büchern steht nix drin. Gibt es eingentlich fälle in denen man den
beispielcode von dir wirklich benutzt ?

EXPORT_C/IMPORT_C sind (sofern ich das jetzt richtig vertanden hab)
Schlüsselwörter (oder wie man dazu sagt) die für DLLs benutzt werden.
wenn ich eine funktion aus einer library benutzen will, dann muss ich
IMPORT_C nehmen und wenn ich eine funktion in einer dll bereitstellen
möchte dann muss ich EXPORT_C nehmen.

Die funktion hat übrigends keine drei punkte als argument. ich hab nur
den reichtigen code raus gemacht da er zeihmlich lang war und die sache
somit nicht mehr auf eine zeile gepasst hätte.


MfG Daniel Düsentrieb

von Chris (Gast)


Lesenswert?

forward-declarations braucht man zum Beispiel bei solchen Abhängigkeiten
wie oben. Manchmal kommt es eben doch vor (auch wenn es dann häufig ein
besseres Design geben mag), dass zwei Klassen sich gegenseitig
benötigen.


Ein (ziemlich schlechtes) Beispiel:
Man hat zwei Klassen, die eine heißt DeviceContext, die andere
Rectangle. DeviceContext hat in etwa die Funktion eines HDC unter
Windows, stellt also eine Abstraktion der Zeichenhardware dar, meistens
des Bildschirms. Rectangle definiert ein Rechteck.

Der Einfachheit halber entscheidet man nun, dass Rectangle einen Zeiger
auf ein DeviceContext-Objekt erhält, um sich jederzeit selbstständig
zeichnen zu können. Ein DeviceContext-Objekt enthält nun aber
seinerseits ein Rectangle, um die gültige Zeichenfläche anzugeben.
Dieses Rectangle darf natürlich kein DeviceContext-Objekt enthalten,
sonst hätte man eine Endlosschleife (dieses Rectangle würde wieder ein
DC enhalten, dieses wieder Rectangle, und so weiter). Also enthält ein
DeviceContext ein Rectangle-Objekt, dessen DeviceContext-Zeiger auf 0
zeigt.

Um diese Klassen zu deklarieren, benötigt man zwingend
forward-declarations:

class DeviceContext;
class Rectangle {
DeviceContext* dc_;
public: Rectangle(DeviceContext* p) : dc_(p) { };
};
class DeviceContext {
Rectangle valid_area_;
public: DeviceContext() : valid_area(0) { };
};


DeviceContext initialisiert den dc_-Zeiger seines Rectangles also mit 0
(der Doppelpunkt beim Konstruktor leitet eine Initialisiererliste ein).

Wichtig ist hier, dass es andersrum nicht funktionieren würde; man kann
also nicht DeviceContext vor Rectangle definieren. Die
DeviceContext-Klasse enhält nämlich eine Rectangle-Instanz, keinen
Zeiger. Eine Instanz darf aber erst verwendet werden, nachdem die
Klasse vollständig definiert wurde. Der Compiler weiß ansonsten nicht,
wie viel Bytes er für DeviceContext reservieren soll (da er die Größe
von Rectangle noch nicht kennt).

von Zotteljedi (Gast)


Lesenswert?

> EXPORT_C/IMPORT_C sind (sofern ich das jetzt richtig vertanden hab)
> Schlüsselwörter (oder wie man dazu sagt)

Als Schlüsselworte werden AFAIK nur Sprachbestandteile (if, return, do
und so Zeugs) bezeichnet. Was Du da hast sind Makros, die vom
Präprozessor durch anderen Code ersetzt werden.

Wenn's um DLLs geht, dann ist es sowieso erstmal
implementierungsabhängig, der Sprachstandard kennt dieses Konzept nicht
(was ihn auch unnötig speziell machen würde, und gerade das will man
nicht).

Wie bereits gesagt wurde, sollte die Dokumentation zu Deinem Compiler
bzw. Deiner Entwicklungsumgebung mehr verraten. Etwas Googeln könnte
auch schon helfen, so scheinen die Makros zu "__declspec(export)"
aufzulösen.

Grundregel: was mit  oder _ anfängt ist Sache des Compilers bzw. der
Implementierung, und wenn man damit rumhantiert wird man generell
unportabel. Ich meine mich zu erinnern, daß es bei C-Compilern für
Win32 auch schon üblich war mit __declspec den DLL-Kram zu handhaben,
es handelt sich also scheinbar um eine (namenlose?) Konvention das
unter Win32 einheitlich zu handhaben.

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.