Ist es möglich jeden Typen in ein char Array zu kopieren?
-
drakon schrieb:
Hmm. Ich würde mal sagen, dass es da Probleme mit padding geben kann. (Kommt natürlich drauf an, was du dort innerhalb machst..).
Wieso sollte das Probleme mit dem Padding geben? Das verstehe ich jetzt nicht so recht. Das sizeof sollte die Padbytes bereits beinhalten und somit sollte auch das char Array bereits genügend gross sein, um diese zusätzlichen Bytes aufzunehmen.
Und ich habe ja geschrieben, dass man möglichst nicht auf den Speicher des Arrays schreiben sollte. Das wäre mir persönlich viel zu gefährlich, da man dann genau wissen müsste, wo der Kompiler welche Bytes hinschaufelt. Der Bereich zwischen Kopie und Rückwandlung kann also ignoriert werden, da ich mal definiere, dass das Array nicht verändert wird.
Grüssli
-
Ich habe zwar keine Ahnung was der Standard dazu sagt, doch ich habe sowas in der Art auch schon gemacht (ebenfalls nur zu Testzwecken rein aus Neugierde) und das hat keine Probleme bereitet.
Denn wenn man mal bedenkt, dass ein Zeiger unabhängig vom Typ immmer die gleiche Größe hat und schlicht und einfach eine Speicheradresse speichert, welche ebenfalls vom Typ unabhängig ist, fällt mir jetzt auch kein Grund ein warum das nicht klappen sollte.
In diesem Zusammenhang stelle ich jetzt einfach mal die vorsichtige Vermutung, dass ein solches Handeln auch nie zu unvorhersehbaren Fehlern führen wird (wenn man alles richtig macht), egal ob das jetzt irgendwo definiert ist oder nicht, schlicht und einfach auf Grund der Natur der Zeiger, einfach nur Zeiger mit typunabhängiger Größe zu sein, welcher auf Speicher zeigt der ebenfalls vom Typ unabhängig ist (abgesehen von der größe)Der Typ den man angibt ist halt einfach eine Info die aussagt, wie weit man ab dieser Speicheradresse lesen soll.
z.B. geht ja auch sowas hier:
double double_var; // double = 8 byte char pchar_var[8] = "tagchen"; // <-- + \0 Ein char ist ja 1 byte und speicher reserviert wird für 8 davon memcpy(&double_var, pchar_var, 8); std::cout << (char*)&double_var << std::endl;Ob das jezt nun Sinn macht oder nicht interessiert bei einem Test ja nicht

EDIT:
Hier auch ein interesanntes Ergebnisint int_var; float float_var = 12.33; memcpy(&int_var, &float_var, 4); std::cout << *((float*)&int_var) << std::endl;Tatsächlich wird hier die 12.33 erhalten, obwohl dieser Wert in einem Sepeicherbereich lag der für einen Int reserviert war.
-
Achso.. Ich habe das hier:
// Am besten wohl gar nicht erst beschreiben

eher bezogen auf das hier gelesen (auch wegen dem Smiley)
// Mach was damit, was auch immer ...
Nich beshreiben was man macht..

Aber ich hatte tatsächlich das beschreiben im Kopf, was sehr wahrscheinlich schief gehen würde..
-
Dravere schrieb:
drakon schrieb:
Hmm. Ich würde mal sagen, dass es da Probleme mit padding geben kann. (Kommt natürlich drauf an, was du dort innerhalb machst..).
Wieso sollte das Probleme mit dem Padding geben? Das verstehe ich jetzt nicht so recht. Das sizeof sollte die Padbytes bereits beinhalten und somit sollte auch das char Array bereits genügend gross sein, um diese zusätzlichen Bytes aufzunehmen.
Ja, Probleme gibts, wenn du das gleiche auf nem anderen System mit anderem Compiler machst, dann kann das Padding anders sein und die Daten passen nicht mehr zusammen. Aber padding kann man auch ausschalten.
-
drakon schrieb:
...
Hmmm, klingt wirklich verwirrend. Ich habe es mal umgeschrieben, für neue Leser.
@Kahino,
Beispiele kann ich auch schreiben und sehen das es geht. Nur beweisen Beispiele überhaupt gar nichts. Erst recht nicht bei fundamentalen Typen. Mein gezeigter Code lässt auch nicht PODs zu.
Vor allem kann man bei solchen Beispielen auch nicht wissen, ob es nicht einfach am Kompiler liegt, da er die Sachen gerade richtig hinschaufelt.
Ich bin dir zwar dankbar für deine Bemühungen, aber viel bringen tut es leider nichts.Vielleicht für die Allgemeinheit, nicht nur Kahino:
Ich hoffe eigentlich darauf, dass sich irgendjemand hier gut im Thema auskennt und mir das relativ schnell und einfach beantworten kann. Falls jemand Lust hat, sich im Standard dazu schlau zu machen, will ich das natürlich nicht verbieten.
Vermutungen sind zwar schön und gut, nur leider kann man mit ihnen keine Vermutung beweisen oder widerlegen.
@systemator (grad noch in der Vorschau gesehen),
Das gilt aber nur, wenn die zwei Programme solche Daten miteinander austauschen. Davon bin ich zwar nicht ausgegangen, aber es ist ein guter Vermerk. Wieder mal das Problem vom nicht standardisierten Binarycode bei C++.Grüssli
-
Die "Hinwandlung" ist so wie ich den Standard auslege erlaubt.
Die "Rückwandlung" ganz sicher nicht.Grund: du hast an der stelle kein "ValueT" konstruiert, also darfst du es auch nicht als "ValueT" ansprechen.
Praktisch gesehen kann natürlich auch ganz furchtbar viel in die Hose gehen, nämlich wenn die Klasse keinen trivialen Copy-Ctor hat (oder u.U. garkeinen Copy-Ctor).Alignment sollte passen, da new grundsätzlich immer Speicher zurückgibt der für alle Objekte die <= N sind (N = Grösse des angeforderten Blocks) passend aligned ist.
Kurz: ja, du darfst aus einem T mittels memcpy einen char-Haufen machen, aber aus dem char-Haufen wird auf legale Weise kein T mehr.
p.S.: Mag sein dass es eine Ausnahme für PODs gibt.
p.p.S.: für T = int, short, ... gibt es *glaube ich* eine Ausnahme, obwohl ich mir nichtmal da 100% sicher bin.
-
padding kann z.b. probleme bei ungraden größen machen:
struct test { char c[5]; }; test *t = new test[2]; char *c = reinterpret_cast<char *>(t); test &t2 = reinterpret_cast<test &>(*c); delete[] t;es kann sein dass die refernez auf ein / drei bytes vor c zeigt. ist aber
unwahrscheilich
-
hustbaer schrieb:
Grund: du hast an der stelle kein "ValueT" konstruiert, also darfst du es auch nicht als "ValueT" ansprechen.
Gutes Argument. Was ist, wenn ich auf den char Haufen zuerst ein "Placement New" für den entsprechenden Typen durchführe? Dann hätte ich ja grundsätzlich ein ValueT konstruiert. Das kopieren sollte funktionieren, und das ansprechen dann auch .. oder?
hustbaer schrieb:
Praktisch gesehen kann natürlich auch ganz furchtbar viel in die Hose gehen, nämlich wenn die Klasse keinen trivialen Copy-Ctor hat (oder u.U. garkeinen Copy-Ctor).
Sehr guter Vermerk. Das sollte man sich aber einfach im Hinterkopf behalten. Also schreiben wir dazu:
static_assert("has trivial copy-ctor");Danke.
@paddi,
Das ist aber ein wenig ein anderer Code als meiner. Du machst hier ein Array von Typen und erst dann ein Cast auf char (und kopierst nicht einmal).
Zudem weiss ich nicht, ob der Kompiler das Padding vor oder nach dem erstellen des Arrays macht. Meiner Meinung ist es nämlich vor. Weiss das einer genauer?Grüssli
-
@Dravere:
Was ist deine Frage genau? Ob es effektiv mit "den üblichen Compilern" geht, oder ob es laut Standard OK ist? Laut Standard ist es nicht OK, effekti gehen tut's aber.Darüber warum es der Standard nicht erlaubt kann man nur mutmassen, aber die übliche Erklärung die kommt, wenn man solche oder ähnliche Fragen stellst ist weil
a) man auch gut ohne diese Erlaubnis auskommt und
b) man "die Implementierung" (den Compiler) nicht unnötig einschränken willEin Compiler könnte z.B. relative Adressen verwenden, z.B. um den VTable zu finden. Kopierst du den gesamten "Inhalt" eines Objekts jetzt Byte für Byte über ein anderes drüber, überschreibst du auch den VTable Pointer. Wenn dieser relativ ist, stimmt er an der neuen Adresse nichtmehr.
Aber wozu soll das ganze überhaupt gut sein? Wenn man voraussetzt dass die Klasse einen trivialen Copy-Ctor und einen trivialen Assignment-Operator hat, dann kann man gleich Placement-New bzw. den Assignment-Operator verwenden, denn wesentlich schneller wird ein memcpy normalerweise auch nicht sein.
-
hustbaer schrieb:
Was ist deine Frage genau? Ob es effektiv mit "den üblichen Compilern" geht, oder ob es laut Standard OK ist?
Zweiteres. Also ob es nach Standard OK ist. Daher ist meine Frage wohl mehr oder weniger beantwortet. Muss mir das dann morgen, wenn ich wieder vollständig ausgeschlafen bin, nochmals durch den Kopf gehen lassen.
Danke für die Erklärung.hustbaer schrieb:
Aber wozu soll das ganze überhaupt gut sein?
Für nichts ausser einem Selbsttest, bzw. dem Füllen von C++ Wissenslücken. Ich möchte mein Wissen über C++ anfangen abzurunden, den letzten Schliff geben, zumindest was den Standard angeht. Damit der neue Standard das schöne Konstrukt dann hoffentlich nicht zu schwer wieder beschädigt

Es sind halt einfach ein paar Fragen, welche ich gerne über C++ noch wissen möchte. Wie ich mich auch dringend nochmals genauer mit std::locale, facet und codecvt auseinander setzen muss oder die Allokatoren nochmals durchgehen. Vielleicht auch die Streams noch einmal genau ansehen, wie sie intern funktionieren, bzw. wie man sie erweitert.
Es ist halt reiner Wissensdurst. Wenn man mich schon mehreren Orten als C++ Nerd beschimpft, dann will ich dem ja auch gerecht werden
Grüssli