Hallo,
ich habe eine Klasse A die als Member einen String hat, ich moechte
diesen jetzt in uint8* konvertieren.
Ich habe es mit reinterpret_cast versucht, das hat jedoch nicht
funktioniert.
Hintergrund des ganzen:
Ein Member von A ist Objekt B.
Objekt B hat einen uint8_t* Buffer als member.
Bisher hatte ich den wert im Konstruktor von A so gesetzt:
B.buffer = (uint8_t*)"Hallo";
Der compiler nimmt das ganze auch an, jedoch zeigt der buffer dann auf
ein literal das auf dem Stack liegt. Das ganze hatte dann einen sehr
schwer zu findenen bug zur folge, da der wert im pointer verloren geht.
Deswegen moechte ich nun mit "new String" das Literal auf den Heap
ablegen.
Weiß jemand wie ich den String casten kann, oder wie ich verhindere das
der Pointer überschrieben wird?
Interessant, dass das Literal selber auf dem Stack liegt und nicht der
Pointer. Muss ich mir mal genauer ansehen. Ansonsten, als schneller Hack
fällt mir ein:
Johannes schrieb:> Hallo,>> ich habe eine Klasse A die als Member einen String hat
von welchem Datentype reden wir da konkret?
Ist das ein std::string?
> Ich habe es mit reinterpret_cast versucht, das hat jedoch nicht> funktioniert.
Mit Casts muss man vorsichtig sein. Casts sind Waffen.
> Ein Member von A ist Objekt B.> Objekt B hat einen uint8_t* Buffer als member.> Bisher hatte ich den wert im Konstruktor von A so gesetzt:>> B.buffer = (uint8_t*)"Hallo";>> Der compiler nimmt das ganze auch an, jedoch zeigt der buffer dann auf> ein literal das auf dem Stack liegt.
Na ja. Nicht wirklich.
"Hallo" ist ein String Literal und existiert als solches während der
kompletten Programmausführung. MIt dem Stack hat das erst mal nichts zu
tun.
> Das ganze hatte dann einen sehr> schwer zu findenen bug zur folge, da der wert im pointer verloren geht.
Der Satz ist für mich nicht ganz verständlich.
Es gibt natürlich ein paar Problemkreise rund um String-Literale, aber
'der Wert im Pointer geht verloren" (was immer das auch heissen mag),
geht nicht verloren.
>> Deswegen moechte ich nun mit "new String" das Literal auf den Heap> ablegen.
Ich denke ernsthaft, du bellst den falschen Baum an.
Zeig mal mehr von deinem Problem. Im Idealfall konstruierst du ein
komplettes Minimalbeispiel, das dein Problem zeigt.
Johannes schrieb:> ich habe eine Klasse A die als Member einen String hat, ich moechte> diesen jetzt in uint8* konvertieren.> Ich habe es mit reinterpret_cast versucht, das hat jedoch nicht> funktioniert.
Welcher Stringtyp?
> Bisher hatte ich den wert im Konstruktor von A so gesetzt:>> B.buffer = (uint8_t*)"Hallo";
Es empfielt sich, das Zeigerziel const zu machen, da darauf nicht
geschrieben werden darf. Und warum uint8_t und nicht einfach char?
> Der compiler nimmt das ganze auch an, jedoch zeigt der buffer dann auf> ein literal das auf dem Stack liegt.
Nein.
> Weiß jemand wie ich den String casten kann, oder wie ich verhindere das> der Pointer überschrieben wird?
Von wem soll der den überschrieben werden?
Karl Heinz schrieb:> von welchem Datentype reden wir da konkret?> Ist das ein std::string?
Ja es handelt sich um einen std::string.
Was das literal betrifft, habe ich mich wahrscheinlich falsch
ausgedrueckt.
Ich glaube nicht, dass das Literal verschwindet, sehr wohl aber der
Pointer.
Die Umgebung des Projektes ist ein Cortex M4 Microcontroller.
Der Controller startete sich innerhalb einer interrupt routine immer
wieder neu wenn ich den Pointer wie oben initalisiere.
Ich kann den Code leider nicht posten, da es sich nicht um ein privates
Projekt handelt (Ich bin Praktikant). Deswegen bin ich auch an uint8_t
gebunden.
Der versuch eines Minimalbeispiels:
Bisher:
// Alte bug "behoben" aber nach dem cast steht in buffer nichts sinvolles.
9
}
10
11
A::Methode()
12
{
13
otherMember->send(MemberWithBuffer);
14
}
15
16
~A()
17
{
18
deletetest;
19
}
20
21
protected:
22
BMemberWithBuffer;
23
C*otherMember;
24
std::string*befehl;
25
}
Mark 99 schrieb:> const char * tmp = "Hello";> B.buffer = (uint8_t*) tmp;
Hat leider nicht funktioniert.
Daher benuteze ich als Notloesung folgendes:
Bisher:
Aus deinem Beispiel kann man leider nicht wirklich etwas entnehmen. Es
hängt zb auch davon ab, wie und wo du ein derartiges A Objekt benutzt.
Wenn ein Pointer innerhalb eines Objektes ungültig ist, dann ist es sehr
oft der Fall, dass bereits das Objekt an sich schon ungültig ist.
In deinem eigenen Interesse:
> Ich kann den Code leider nicht posten, da es sich nicht um ein> privates Projekt handelt (Ich bin Praktikant).
Dann nimm die Klassen, speck sie ab und bau ein neues Minimalbeispiel,
in dem du die Verwendung dieser Klasse so gestaltest, wie sie auch in
deinem realen Projekt ist. Teste, ob sich immer noch das gleiche Problem
zeigt und wenn ja, poste es.
In dem was du gepostet hast, ist so erst mal nichts falsch und es ist
kein Grund erkennbar, warum da irgendwas abstürzen sollte. Das ist auch
kein Kunststück, weil man aus den Schnipseln nicht wirklich etwas
entnehmen kann. Eines kann ich dir aber auch so sagen: Die Verwendung
von dynamisch allokierten Objekten wird dein Problem nicht lösen. Das
setzt dem ganzen nur noch eine zusätzliche Dimension auf.
Um es klar herauszustellen: Dein Minimalbeispiel muss vollständig,
compilierbar und lauffähig sein! Auch wenn es abstürzt (gerade dann). Es
geht darum, dass wir hier auf dieser Seite des Bildschirms alles haben,
um damit ein komplettes Programm bauen zu können). Zum Beispiel sollte
auch die send Funktion zumindest in Grundzügen das tun, was die echte
Funktion auch macht.
Nur dann kann man analysieren, was da zur Laufzeit tatsächlich passiert
und wo du deinen Fehler hast. Das Speichern der Adresse eines
String-Literals ist es jedenfalls nicht, solange die send Funktion nicht
versucht, den Inhalt von *buffer zu verändernd, was hier mangels Code
keiner beurteilen kann.
Und ja. Wenn das Erstellen so eines Minimalbeispiels eine halbe Stunde
oder eine ganze Stunde dauert, dann dauert das eben eine halbe oder eine
ganze Stunde. Verglichen damit, dass du schon 19 Stunden durch fehlende
Information hast ungenutzt verstreichen lassen und wahrscheinlich vorher
auch schon eine Zeit lang gesucht hast, benötigt das Zusammenstellen
vergleichsweise wenig Zeit und dann kann dir hier auch wer helfen, das
Problem zu finden und dich beraten, wie man es lösen kann. Dein Ad-Hoc
Ansatz ist ziemlich sicher keine Lösung. Das kann man auch so erkennen,
auch wenn nicht klar ist, was eigentlich das eigentliche Problem ist.
Wenn das
std::string str = string("Hallo");
funktioniert, dann sollte auch mit den üblichen Methoden auf den
eigentlichen Speicherbereich des Strings zugegriffen werden können:
const char* cStr1 = str.c_str();
oder
const char* cStr2 = &str[0];
Warum, weshalb und seit wann wird hier erklärt:
http://herbsutter.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-be-contiguous/#comment-483
Ich habe inzwischen nochmal nachgesehen. Also wenn sich nicht ganz
gewaltig was in C++ geändert hat, dann kann ein String Literal wie
"Hallo" niemals auf dem Stack liegen. Ein Zeiger darauf schon, das
Literal selber aber nicht, das hat Static Storage Duration. D.h. es muss
vor Eintritt in main() existieren, genau einmal und bewegt sich nicht.
Wenn Du zum "Hurra es geht"! kommst, beachte bitte, dass Du durch das
"verteilen" eines Zeigers, die Kapselung der Klasse durchbrichst.
Wundere Dich also nicht, wenn Dich die Konstrukteure anschließend an die
Wand stellen. Nach dem Motto: Vorher war alles OK, jetzt haben wir
unerklärliche Fehler.
Es gibt nämlich nichts schöneres, als wenn man einen Sündenbock hat.
Nach der zehnten Änderung weis sowieso keiner mehr, woran es gelegen
hat.
Hallo nochmal und vielen Dank fuer eure Hilfe!
Gestern bin ich nicht mehr dazu gekommen hier nochmal rein zu schauen
Wie Karl Heinz schon vermutet hat, versucht eine von send() ausgeloeste
interrupt routine den *buffer tatsaechlich zu aendern.
Karl Heinz schrieb:> Das Speichern der Adresse eines> String-Literals ist es jedenfalls nicht, solange die send Funktion nicht> versucht, den Inhalt von *buffer zu verändernd, was hier mangels Code> keiner beurteilen kann.
Das Literal, auf das der Buffer zeigt liegt jedoch zu diesem Zeitpunkt
im Flashspeicher des Controllers. Daher gibt es einen Zugriffsfehler,
der auch von Code den ich nicht geschrieben habe abgefangen wird und
dafuer sorgt das, dass Programm sich neustartet.
Johannes schrieb:> Hallo nochmal und vielen Dank fuer eure Hilfe!>> Gestern bin ich nicht mehr dazu gekommen hier nochmal rein zu schauen> Wie Karl Heinz schon vermutet hat, versucht eine von send() ausgeloeste> interrupt routine den *buffer tatsaechlich zu aendern.
Das ist zwar etwas ungewöhnlich für eine Funktion, die send() heisst,
aber ich vermute mal, du kannst daran nichts ändern.
Wenn ich du wäre, würde ich darauf drängen, dass diese Funktionalität
geändert wird. Eine Funktion, die etwas versenden soll, hat sich nicht
an den Daten zu vergreifen.
Wie auch immer.
Das hier
1
A()
2
{
3
command[0]='H';
4
command[1]='a';
5
command[2]='l';
6
command[3]='l';
7
command[4]='o';
8
MemberWithBuffer.buffer=command;
9
// Funktioniert ist aber sehr umstaendlich
kannst du ein wenig vereinfachen
1
strcpy(command,"Hallo");
Das hängt allerdings ein '\0' ans Ende an. Wenn das nicht gewünscht ist,
dann kannst du immer noch memcpy benutzen
1
memcpy(command,"Hallo",strlen("Hallo"));
aber eigentlich würde ich darauf drängen, dass eine send-Funktion die
Daten in Ruhe lässt. Das würden von 100000 Programmierern 99999 genau
so erwarten, es wäre logisch und auf lange Sicht gesehen ist das sicher
die bessere Option. In einer send Funktion gibt es normalerweise auch
gar keinen Grund dafür, sich daran zu vergreifen.