www.mikrocontroller.net

Forum: PC-Programmierung Hilfe


Autor: Gre Bre (stabilo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Liege ich hier komplett falsch oder wird hier von einem Wert die
Kommastelle bestimmt

char cDataOut[11];

  cDataOut[1] = x / 1000 + 48;
  cDataOut[2] = fmod(x, 1000) / 100 + 48;
  cDataOut[3] = fmod(x, 100) / 10 + 48;
  cDataOut[4] = fmod(x, 10) + 48;

  cDataOut[5] = 0x2c; // ','


  cDataOut[6] = y / 1000 + 48;
  cDataOut[7] = fmod(y, 1000) / 100 + 48;
  cDataOut[8] = fmod(y, 100) / 10 + 48;
  cDataOut[9] = fmod(y, 10) + 48;

  cDataOut[10] = 0x3b; // ';'
  cDataOut[11] = '\0';

  putsUART1((unsigned int *) cDataOut);

  return 0;
}

Autor: Markus Volz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi gre bre,

ja, Du liegst falsch.

Hier passiert zweierlei: Das schlimmste zuerst: Es wird außerhalb des
vereinbarten Arrays cDataOut im Speicher ein 0-Byte abgelegt. Die
Arrayindices von cDataOut gehen nicht von 1 bis 11 sondern von 0 bis
10!!!

Als zweites wird hier ein float-Wert, der aus einem (vermutlichen) int
für die Vorkommastellen und einem zweiten int für die Nachkommastellen
mit jeweils 4 Stellen in einen ASCII-String gewandelt. Format:
vvvv,nnnn;\0

Zur eigentlichen Vorgehensweise sage ich besser nichts, ich kenne die
Umgebung nicht. Es gibt in C/C++ wesentlich effizientere Methoden.

Markus

Autor: Gre Bre (stabilo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für deine Hilfe

du sagst du kennst eine effizientere Methoden in C++

Autor: Gre Bre (stabilo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast recht am Hyperterminal werden Daten in diesem Format
0000,0085;0001,0087;......ausgegeben.

Autor: Gre Bre (stabilo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kennst du vielleicht eine gute Seite wo man das nachlesen kann
oder unter welchen Suchbegriff das zu finden ist

Autor: Markus Volz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi gre bre,

es werden bestimmt bald Aufschreie aus der C++-Abteilung kommen, aber
das kompakteste, das ich kenne, ist in diesem Fall sprintf:

sprintf(cDataOut,"%04d,%04d;",x,y);

Kompakter geht es meiner Meinung nach nicht. Dadurch sieht man auch auf
einen Blick, was hier passiert.

Ein Problem gibt es bei der Konvertierung, das gilt aber für alle
Lösungen. Es muß sichergestellt sein, daß x und y nur im Wertebereich
von 0 <= x,y <= 9999 liegt. Sonst schreibt die Software wieder in
Speicherbereiche, in denen sie nichts verloren hat.

Ich habe heute Morgen leider zu wenig Zeit, um noch ausführlich auf
weitere Lösungen einzugehen. Ich denke, daß zu diesem Thema sicher
andere auch etwas beitragen werden. Falls nichts mehr kommt, werde ich
heute Abend mal schauen, wo es noch klemmt.

Ach ja, Du hast auch noch nach Suchbegriffen gefragt: Englisch
formatting, ggf. auch streams (wegen den C++-Profis ;-)), deutsch dann
Formatierung

Gruß
Markus

Autor: Gre Bre (stabilo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielleicht hört sich das für einen profi in C++ dumm, an aber wie werden
die werte von 0-9999 begrenzt

Autor: Gre Bre (stabilo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Entschuldigung __Beistrichfehler____
.....dumm an,.....

Autor: Markus Volz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo gre bre,

dumme Fragen gibt's nicht, nur dumme Antworten.

Bei der Begrenzung gibt es, wie fast immer beim Software entwickeln,
viele Möglichkeiten.

Die einfachste ist die, wenn dort, wo x und y gesetzt werden,
sichergestellt ist, daß deren Wertebereich tatsächlich nur von 0 bis
9999 gehen kann, weil x und y einen Punkt in einem entsprechenden
Koordinatensystem darstellen.

Ansonsten VOR der Konvertierung den Wertebereich abprüfen und im
negativen Fall einen Fehler erzeugen:

if ( x >= 0 && x <= 9999 && y >= 0 && y <= 9999 )
{
    sprintf(...);
}
else
{
    // Fehler melden, in C++ ggf. eine Exception auslösen
}

Wie Du das in Deinem Code letztendlich umsetzt, hänge sehr stark von
den Gegebenheiten ab. So könnten z.B. x und y unsigned sein, dann ist
der Test auf ">= 0 überflüssig.

Es wäre auch möglich, den Sting cDataOut so groß zu machen, daß auf
jeden Fall beim Konvertieren kein Bufferoverflow stattfinden kann. Ein
32-Bit-int hat als Dezimalzahl max. 11 Stellen, mit Vorzeichen 12. Das
Ganze mal 2 und noch die Zeichen ",", ";" und die 0 am Ende, macht
zusammen 25 Zeichen. Wenn Du  char cDataOut[32] deklarierst, bist Du
auf der sicheren Seite.

Gruß
Markus

Autor: Gre Bre (stabilo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Licht am Ende des Tunnel mit deiner Unterstützung

kann man den Sting cDataOut beliebieg groß machen


noch einmal wie kommst du auf die 0-9999


und dann glaube  habe ichs


nochmals danke für deine unterstützung

Autor: Markus Volz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo gre bre,

cDataOut kann man fast beliebig groß machen. Fast soll heißen, daß die
Größe i.d.R. durch den Stack, die Größe des Heaps (dynamischer
Datenspeicher), die Größe des tatsächlichen Arbeitsspeichers und
normalerweise durch den 32-Bit-Integerbereich von Größenangaben
beschränkt. Große Datenpuffer, also auch Strings sollte man in C++ mit
new allokieren, mit delete wieder freigeben. In C geht das mit
malloc/calloc und free.

char *cDataOut = malloc(100000); // 100000 Bytes Speicher anfordern
...
free(cDataOut);

Allerdings ist hier sehr große Disziplin angesagt. Es ist eine der
häufigsten und vor allem am schwierigsten zu findenden Fehlerquelle in
C/C++, wenn Speicher zwar allokiert, aber nicht wieder frei gegeben
wird.

char* cDataOut = malloc(1000);
...
cDataOut = malloc(2000);
...
free(cDataOut)

Die ersten tausend Bytes sind bis zum nächsten Programmstart
unwiederbringlich futsch. Wenn man das in einer Schleife veranstaltet,
platzt recht bald der Heap.

Zur Frage nach dem begrenzten Wertebereich: Wenn man das Programm etwas
genauer anschaut, sieht man, daß für den String im Format "xxxx,yyyy;"
ein String mit genau 11 Bytes vorgesehen wurde. Ein Byte für die
abschließende 0, ein Komma, ein Semikolon. Bleiben noch 8 Bytes für die
beiden Zahlen. Macht je 4 Stellen, also 0 bis 9999. Dies ist aber nur
ein Indiz. In Programmcode passiert folgendes:

cDataOut[1] = x / 1000 + 48;

In dieser Zeile wird eine ganzzahlige Division durch 1000 durchgeführt,
dann das ASCII-Zeichen '0' dazu addiert. 0 / 1000 = 0, +  '0' =
'0'. 999 / 1000 = 0, ..., 1000 / 1000 = 1, + '0' = '1', ...

cDataOut[2] = fmod(x, 1000) / 100 + 48;

fmod ermittelt den ganzzahligen Divisionsrest von x / 1000, beide
werden erst mal in float-Werte konvertiert. Dann Wird durch 100 geteilt
und wieder '0' dazu addiert. Effektiver geht das übrigens so:

char hunderter = ( x / 100 ) % 10 + '0'; // ohne float-Konvertierung

cDataOut[3] = fmod(x, 100) / 10 + 48;
cDataOut[4] = fmod(x, 10) + 48;

Den Rest kannst Du Dir ja selbst ermitteln. Jedenfalls werden x und y
4-stellig nach cDataOut konvertiert.

Gruß
Markus

Autor: Gre Bre (stabilo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sprintf(cDataOut,"%04d,%04d;",x,y); hier in deiner verkürzten
schreibweise passiert das gleiche


Herzlichen Dank für deine Bemühungen

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.