Guten Tag,
ich muss mich im Moment mit "Objektbasiertem C" auseinandersetzen und
habe so meine Probleme.
Kurze Info vorab ich muss das im Anhang zu findende Klassendiagramm
programmieren.
Ich habe einen kleinen Teil versucht umzusetzen und bekomme einen
Speicherzugriffsfehler beim ausführen.
Hier die main.c
1
#include"LED.h"
2
#include"PWMLed.h"
3
#include<stdio.h>
4
#include<stdlib.h>
5
6
7
intmain()
8
{
9
10
class_LEDled1=NewClassLed(1);// Led Status zum Anfang 1
11
12
printf("LED ist %d\n",led1->getStatus(led1));
13
14
free(led1);
15
16
return0;
17
}
Hier erstelle ich eine LED und möchte ihren Status einfach nur ausgeben.
Patti W. schrieb:> ich muss das im Anhang zu findende Klassendiagramm> programmieren
"Ich muss" heißt doch sicher, dass du gerade eine Vorlesung besuchst
oder anderweitig mehr zum Thema weißt oder...?
Du solltest bei deiner new_class_led Funktion nicht nur led->Status
setzten, sondern eben auch led->getStatus = &getstatus;
Ansonsten zeigt der Funktionspointer getStatus nirgendwo hin.
Nase schrieb:> Patti W. schrieb:>> ich muss das im Anhang zu findende Klassendiagramm>> programmieren>> "Ich muss" heißt doch sicher, dass du gerade eine Vorlesung besuchst> oder anderweitig mehr zum Thema weißt oder...?
Jain, sitze zu Hause und versuche Stoff auszubereiten, da der Prof sagen
wir keine "Ich bin dein Freund Haltung" besitzt und auf solche Fragen
ehr entblößt reagiert. Nett formuliert.
Deshalb wäre ich eurer Hilfe hier sehr dankbar.
Peter K. schrieb:> Du solltest bei deiner new_class_led Funktion nicht nur led->Status> setzten, sondern eben auch led->getStatus = &getstatus;>> Ansonsten zeigt der Funktionspointer getStatus nirgendwo hin.
Top :) Solche Sachen vergisst man dann natürlich. Hat funktioniert.
Ich würde dir aber wegen der Übersichtlichkeit vorschlagen dass du eine
new Funktion wie in C++ implementierst, die dir einfach nur Speicher
reserviert und von der Klasse den Konstruktor aufruft, dadurch wird das
Anlegen von Klassen vereinheitlicht.
Ich hab im Internet vor einiger zeit mal einen Code gefunden indem dass
so implementiert war, das ging irgendwie mit Virtuellen Tabellen, also
alles in etwa so wie es auch der C++ Compiler macht. Da war dann auch
Polymorphie möglich usw.
beric schrieb:> Aber wozu willst du getStatus als Pointer haben? Soll der überladen> werden? (Also "virtual" in C++)? Wenn nicht, kannste das sein lassen.
genau das möchte ich auch noch ausprobieren, werde mal berichten wenn
ich es fertig habe.
Peter K. schrieb:> Ich würde dir aber wegen der Übersichtlichkeit vorschlagen dass du eine> new Funktion wie in C++ implementierst, die dir einfach nur Speicher> reserviert und von der Klasse den Konstruktor aufruft, dadurch wird das> Anlegen von Klassen vereinheitlicht.>> Ich hab im Internet vor einiger zeit mal einen Code gefunden indem dass> so implementiert war, das ging irgendwie mit Virtuellen Tabellen, also> alles in etwa so wie es auch der C++ Compiler macht. Da war dann auch> Polymorphie möglich usw.
Klingt gut. Ich werde nachher für ein RaspberryPi Projekt eine
"Einparkhilfe" mit dieser OOP realisieren müssen und werde mir deinen
Tipp da zu Gemüt führen. Danke
du definierst hier:
class_LED led1 = NewClassLed(1); // Led Status zum Anfang 1
die variavble led1 statisch und resevierst deren Speicherplatz nicht mit
malloc() oder new() daher ist die freigabe des Speichers mit
free(led1);
nicht nur unötig sondern schädlich. das dürfte die zeile sein, die den
speicherzugriffsfehler verursacht. Speicherplatz statisch vereinbarter
variablen wird automatisch freigegeben, wenn der gültigkeitsbereich der
variable verlassen wird.
Decius schrieb:> die variavble led1 statisch und resevierst deren Speicherplatz nicht mit> malloc() oder new() daher ist die freigabe des Speichers mit
Das ist C und nicht C++ die Funktion NewClassLed verwendet malloc
Decius schrieb:> du definierst hier:>> class_LED led1 = NewClassLed(1); // Led Status zum Anfang 1>> die variavble led1 statisch
Nein, class_LED ist ein Zeiger-Typ.
Wie man sieht, wird die Verständlichkeit durch das Verstecken des
Zeigers in einem typedef nur verringert. "struct Led *" wäre nun auch
nicht viel weniger Tipparbeit.
Clemens L. schrieb:> Wie man sieht, wird die Verständlichkeit durch das Verstecken des> Zeigers in einem typedef nur verringert. "struct Led *" wäre nun auch> nicht viel weniger Tipparbeit.
Da stimme ich dir zu dass das Verstecken eines Zeigers in einem Typedef
nicht günstig ist, aber bensonders beim Objektorientierten zu
Programmieren wird das oft gemacht weil man damit den Eindruck
vermitteln möchte es handelt sich um das Objekt und nicht um einen
Zeiger auf das Objekt.
Dann definiert man noch eine delete Funktion und es sieht aus wie C++.
Warum man nicht einfach direkt C++ verwendet ist schleierhaft... Da
könnte man direkt gebraucht von schönen Dingen wie shared_ptr oder
unique_ptr machen, sodass man zwar dynamischen Speicher verwenden, aber
das Freigeben ("delete") gar nicht mehr vergessen kann!
Programmierer schrieb:> Warum man nicht einfach direkt C++ verwendet ist schleierhaft...
C++ ist einfach für viele ein Rotes Tuch, siehe Linus Torvald.
Andererseits war es früher auch so dass die ersten C++ Compiler einfach
nur Übersetzer auf C Code waren und dieser wurde dann kompiliert.
Zudem ist es oft von Vorteil C zu verwenden wenn man wert auf
Binärkompatibilität legt. C++ hat nämlich keine definierte ABI
Programmierer schrieb:> Warum man nicht einfach direkt C++ verwendet ist schleierhaft...
Es geht hier wohl um den Lerneffekt. shared_ptr & Co. sind wenig
hilfreich um Grundlagenwissen zu vermitteln.
Das malloc in NewClassLed könnte auch null livern. Ein constructor soll
Initialisieren, nicht Speicher reservieren. Ich würde dass so
schreiben*:
1
voidLed_init(struct*Ledled,intstatus){
2
led->status=status;
3
}
4
5
intLed_getStatus(structLed*led){
6
returnled->status;
7
}
8
9
intmain(){
10
structLedled;
11
12
Led_init(&led,1);// Led Status zum Anfang 1
13
14
printf("LED ist %d\n",Led_getStatus(&led1));
15
16
return0;
17
}
* zumindest wenn ich nicht zu faul wäre und statdessen auf den getter
verzichten und die Init methode durch einen designated initializer
ersetzen würde.
Peter K. schrieb:> Zudem ist es oft von Vorteil C zu verwenden wenn man wert auf> Binärkompatibilität legt. C++ hat nämlich keine definierte ABI
Das ABI ist doch auch in C nicht im Standard geregelt, sondern in der
Compilerdoku.
Msvc ist nicht binärkompatibel zu gcc.
Wo ist der Unterschied zu C++?
bal schrieb:> Wo ist der Unterschied zu C++?
Naja beim C++ sind Programme die mit unterschiedlichen Compilerflags
programmiert wurden oder die von zwei unterschiedlichen Versionen des
selben Compilers kompiliert wurden nicht binärkompatibel.
Das ist auch der Grund warum viele C++ Programm ein Pluginsystem in C
haben weil einfach dadurch ein Einheitliches Interface gibt.
Btw ich habe ein in C++ geschriebenes Programm mit C Pluginsystem,
kompiliert mittels g++ und Plugins die ich mit dem Msvc kompiliert habe
und das Funktioniert Problemlos.
Bei einem Pluginsystem in C++ funktionierte das nicht.
http://gcc.gnu.org/onlinedocs/gcc/Compatibility.html
Most platforms have a well-defined ABI that covers C code, but ABIs that
cover C++ functionality are not yet common.
Peter K. schrieb:> bal schrieb:>> Wo ist der Unterschied zu C++?>> Naja beim C++ sind Programme die mit unterschiedlichen Compilerflags> programmiert wurden oder die von zwei unterschiedlichen Versionen des> selben Compilers kompiliert wurden nicht binärkompatibel.
Das ist in C ganz genau gleich.
Sie können oder können nicht binärkompatibel sein. Welches davon der
Fall ist bestimmt der Compilerhersteller.
> http://gcc.gnu.org/onlinedocs/gcc/Compatibility.html> Most platforms have a well-defined ABI that covers C code, but ABIs that> cover C++ functionality are not yet common.
Anders rum wird ein Schuh daraus.
Nicht C hat ein einheitliches ABI, sondern die zugrundeliegenden
Betriebssysteme definieren durch ihre Programmierschnittstellen ein ABI.
Da ein Betriebssystem aber nicht davon ausgehen kann, dass ein in C++
geschriebenes Programm auf ihm läuft, müssen diese ABI naturgemäss am
kleinsten gemeinsamen Nenner ansetzen. Auf einer VAX war es problemlos
möglich, von Fortran aus Lisp Code aufzurufen. Das hat aber nichts mit
den definierten Eigenschaften von Fortran oder Lisp zu tun, sondern
damit, das DEC für sich entschieden hat, in allen Sprachen einheitliche
Schnittstellen auf Binärcode Ebene zu benutzen. Deshalb konnte man von
Pascal auch PL/I Code aufrufen, der eine Fortran Subroutine zur
Berechnung eines Problems benutzt, das mit Lisp optimiert wurde.
Karl H. schrieb:> Nicht C hat ein einheitliches ABI, sondern die zugrundeliegenden> Betriebssysteme definieren durch ihre Programmierschnittstellen ein ABI.
Wieder mal was dazu gelernt ;)
Worauf ich aber eigentlich raus wollte es gibt durchaus noch Gründe
warum man in C Objektorientiert programmiert und nicht einfach C++
nimmt. Wobei in diesem Fall ist es vermutlich nur eine Übung um zu
zeigen obwohl C Prozedural ist kann ich Objektrorientiert arbeiten wenn
man möchte.