Forum: PC-Programmierung Hilfe


von Gre B. (stabilo)


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;
}

von Markus Volz (Gast)


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

von Gre B. (stabilo)


Lesenswert?

Danke für deine Hilfe

du sagst du kennst eine effizientere Methoden in C++

von Gre B. (stabilo)


Lesenswert?

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

von Gre B. (stabilo)


Lesenswert?

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

von Markus Volz (Gast)


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

von Gre B. (stabilo)


Lesenswert?

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

von Gre B. (stabilo)


Lesenswert?

Entschuldigung __Beistrichfehler____
.....dumm an,.....

von Markus Volz (Gast)


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

von Gre B. (stabilo)


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

von Markus Volz (Gast)


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

von Gre B. (stabilo)


Lesenswert?

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


Herzlichen Dank für deine Bemühungen

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.