Forum: PC-Programmierung Stringmember in uint_8 konvertieren


von Johannes (Gast)


Lesenswert?

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?

von Mark 99 (Gast)


Lesenswert?

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:
1
const char * tmp = "Hello";
2
B.buffer = (uint8_t*) tmp;

von Mark 99 (Gast)


Lesenswert?

Hach, noch besser, in C++ 11:
1
B.buffer = u8"Hallo";

von Karl H. (kbuchegg)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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?

von Johannes (Gast)


Lesenswert?

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:
1
Class A
2
{
3
  public 
4
  A()
5
  {
6
   MemberWithBuffer.buffer = (uint8_t*)"Hallo"; // Verursacht fehler
7
   
8
  }
9
10
  A::Methode()
11
  {
12
   otherMember->send(MemberWithBuffer);
13
  }
14
15
  protected:
16
  B MemberWithBuffer;
17
  C *otherMember;
18
}

Idee von mir:
1
Class A
2
{
3
  public 
4
  A()
5
  {
6
   this->befehl = new string("Hallo");
7
   MemberWithBuffer.buffer = reinterpret_cast<uint8_t*>(test);
8
// 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
   delete test;
19
  }
20
21
  protected:
22
  B MemberWithBuffer;
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:
1
Class A
2
{
3
  public 
4
  A()
5
  {
6
   command[0] = 'H';
7
   command[1] = 'a';
8
   command[2] = 'l';
9
   command[3] = 'l';
10
   command[4] = 'o';
11
   MemberWithBuffer.buffer = command; 
12
   // Funktioniert ist aber sehr umstaendlich
13
   
14
  }
15
16
  A::Methode()
17
  {
18
   otherMember->send(MemberWithBuffer);
19
  }
20
21
  protected:
22
  B MemberWithBuffer;
23
  C *otherMember;
24
  uint8_t command[20];
25
}

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
von Arc N. (arc)


Lesenswert?

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

von Mark 99 (Gast)


Lesenswert?

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.

von Amateur (Gast)


Lesenswert?

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.

von Daniel A. (daniel-a)


Lesenswert?

kompiliere mit debug informationen und nutze valgrind, dann findest du 
die wahren ursprünge der übel.

von Johannes (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
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.