Der Konstruktor bietet die Möglichkeit, einen Pointer zu übergeben.
Somit kann ich quasi eine beliebige Speicheradresse in die Klasse ABC
konvertieren, allerdings erstelle ich ja nur ein neues Objekt, das
dieselben Werte besitzt wie die Speicheradresse+Offsets. Es sei mal
dahin gestellt ob an der entsprechenden Position sinnvolle Daten stehen.
Im Speicher steht oben abgebildete Klasse ungefähr so im Speicher:
[testvar][testvar2][testvar3]
Gibt es jetzt eine Funktion wie ich sagen kann: Ab genau dieser
Speicheradresse bitte in ein Objekt der Klasse ABC umwandeln und ich mir
somit den "Umweg" über den Konstruktor und die Umkopiererei sparen kann?
Beispiel:
Adresse: ... #1 #2 #3 #4 #5 #6 #7 #8 #9 #A ...
Speicher: ... 01 02 f1 12 34 67 78 af d1 f2 ...
^- Pointer (*data)
Aufgabe:
"Mache mir aus *data (Pointer auf #4) ein Objekt der Klasse ABC".
Ergebnis:
myobj
{
testvar1 = 0x12;
testvar2 = 0x34;
testvar3 = 26488; // entspricht: 0x6778
}
Ist es irgendwie möglich? Bietet C/C++ eine Möglichkeit "mit Gewalt"
irgendeinen Speicherbereich zu einem Objekt zu casten? Ist einfach nur
rein Interesse halber ... ich finds immer wieder schön, was für
Schweinereien C so alles zulässt ;)
Generell ist es keine gute Idee, einen Pseudo-Kopierkonstruktor - darum
handelt es sich hier - mit void * - Parameter zu bauen.
Die etwas bessere Lösung ist ein normaler Kopierkonstruktor:
ABC::ABC(ABC const &data)
und casten des void-Pointers beim Aufruf auf ABC * :
ABC *pABC = new ABC(*(ABC *) void_ptr);
Die allerbeste Lösung ist der Kopierkonstruktor und korrekte Typisierung
des Speicherbereiches, der kopiert werden soll - es gibt keinen Grund,
das nicht zu tun und erspart im Zweifelsfall viel Ärger, der durch
solchen Murks mit void-Pointern zustandekommen kann.
Statt dem C-cast sollte man auch einen C++ - cast verwenden.
Kann man eigentlich sicher sein, dass der Compiler aus der gleichen
Klassendefinition immer dieselbe Reihenfolge an Bytes im Speicher
erzeugt?
class ABC
{
public:
unsigned char testvar1;
unsigned char testvar2;
unsigned int testvar3;
}
Steht danach im Speicher immer das Array {testvar1, testvar2,
testvar3} oder könnte es auch sein, dass die Reihenfolge geändert wird
oder dass noch andere Werte dazwischen gespeichert werden? {testvar3,
testvar2, variable hans, testvar1}?
Hi
es wird vom C++ Standard garantiert das die Membervariablen in der
Reihenfolge im Speicher liegen in der sie deklariert sind. Es kann aber
vorkommen das esLöcher gibt -> Alignment.
Matthias
> Kann man eigentlich sicher sein, dass der Compiler aus der leichen> Klassendefinition immer dieselbe Reihenfolge an Bytes im Speicher erzeugt?
Die Reihenfolge ist immer die in der Definition angegebene Reihenfolge -
wie in C auch.
Allerdings spielt das Alignment eine wichtige Rolle bei der Festlegung
der Relativadressen der Komponenten:
Bei Alignement 2 z.B., beginnen die Komponenten immer auf geraden
Adressen, was ggf. durch 'Padding Bytes' erzwungen wird.
Bei gleichem Alignement erzeugt der Compiler aus einer bestimmten
Definition immer dasselbe Speicherlayout - anderenfalls wären Typecasts
ziemlich sinnlos.
In C++ sollte man nicht blind darauf vertrauen, dass das erste Element
eines Objekts an Offset 0 liegt. Spätestens bei der ersten virtual
member funktion ist das nicht mehr der Fall. Und bei multiple
inheritance kann auch die Reihenfolge von Elementen durcheinander
geraten.
M.a.W: Finger weg von solchen Spielchen in C++. Ist eine Zeitbombe die
irgendwann hochgeht.
> M.a.W: Finger weg von solchen Spielchen in C++. Ist eine Zeitbombe die> irgendwann hochgeht.
Das stimmt so nicht:
Murksereien in C++ werden mit bösen Fehlern bestraft. Bei C++ muß man
sich so einigen in C völlig üblichen Pfusch abgewöhnen. Insbesondere
Typecasts sollte man meiden, wo immer möglich.
Die wichtigste Regel für C++ - Programmierer:
Strikte Einhaltung der C++ - Regeln.
Dann ist C++ eine sehr mächtige und zuverlässige Sprache.
Anderenfalls sitzt man wirklich auf einer Zeitbombe. Das ist aber nicht
ein Mangel der Sprache, sondern in aller Regel mangelhafte Beherrschung
von C++.
Kleiner Tipp für den Umstieg von C auf C++: Datenstrukturen, die auch
ein C-Compiler versteht, verhalten sich in C und C++ gleich.
Hallo,
da kam ja schon einiges an Rückmeldungen. Also der Hintergrund ist der
folgende: Über einen seriellen Datenkanal tröpfeln die Bytes in einen
unsigned char-Puffer. Dabei entsprechen 32 Bytes immer einem Objekt
einer Klasse. Im Puffer kann immer nur ein Paket sein. Nun muß ich aus
dieser 32 Byte langen Datenwurst ein Objekt einer Klasse erzeugen. Mit
meiner Konstruktor-Methode klappt das prima, wie das mit einem
Kopierkonstruktor funktionieren soll, müsste man mir noch erklären? Also
das Konstrukt an sich ist klar, aber wie weise ich den Variablen dann
die Werte zu? Ein weiterer Gesichtspunkt ist es Speicherplatz zu sparen,
deshalb werden fast ausschließlich Nutzdaten (3-4 Steuerbytes)
übertragen.
In solchen Fällen bietet sich an, eine Basisklasse mit den allen
Varianten gemeinsamen Daten zu definieren, und für jede Variante von der
Basisklasse einen Typ abzuleiten, der die zusätzlichen Daten beschreibt.
(Natürlich keine virtuelle Basisklasse!)
Das setzt allerdings voraus, daß es gemeinsame Headerdaten gibt.
Wenn dann Daten ankommen, legt man zumächst einen Pointer der
Basisklasse auf den Anfang des Puffers, stellt fest, was es für ein Typ
ist und castet anschließend den Basisklassenzeiger in den passenden
abgeleiteten Zeigertyp um.
Dann hat man einen Zeiger auf den richtigen Datentyp, mit dem man
weiterarbeiten kann.
Uhu Uhuhu wrote:
>> M.a.W: Finger weg von solchen Spielchen in C++. Ist eine Zeitbombe die>> irgendwann hochgeht.>> Das stimmt so nicht:
Worin bitte weicht deine Aussage von meiner ab? Ich schrieb "Finger weg"
von solchen Typecasts, von Annahmen über Speicherlayouts etc, du
schreibst "keinen Pfusch".
@ Andreas Kaiser
Bisher war nicht die Rede von virtuellen Funktionen oder multiple
Inheritance -- mit gutem Grund, denn das macht im Kontext des OP auch
überhaupt keinen Sinn.
Und daraus dann auch noch den 'Ratschlag' abzuleiten, 'die Finger davon
zu lassen', ist - milde ausgedrückt - kontraproduktiv.
Im übrigen gibt es nur eine Ausnahme von der Regel, daß Basisklassen in
der Reihenfolge ihrer Nennung im Speicher stehen: Wenn virtuelle
Basisklassen im Spiel sind.
Praktisch spielt diese Ausnahme aber keine Rolle, weil dieses
Irrsinnskonstrukt so gut wie nie verwendet wird.
> Und daraus dann auch noch den 'Ratschlag' abzuleiten, 'die Finger davon> zu lassen', ist - milde ausgedrückt - kontraproduktiv.
Ich glaube ich verstehe, wo das Missverständnis liegt. Er sollte nicht
die Finger von C++ lassen, sondern von bösen Spielchen wie den gezeigten
casts. Und da sind wir wohl nicht weit auseinander.
Ich benutze ja selber gern C++ für Controller.
Hallo,
also die Variante mit dem Kopierkonstruktor wie oben beschrieben hab ich
hinbekommen, es funktioniert. Sieht auch zugegebenermaßen etwas schöner
aus, wenn man nicht irgendwelche Pointer addieren muß, sondern direkt
die Attribute des "Originals" angeben kann.
Vielen Dank.
> Gibt es nicht in der boost library eine Klasse zum serialisieren von> Daten?
Falls es sich um ein µC-Projekt handelt, würde ich davon abraten. Das
gibt leicht eine Codeinflation.