Forum: Compiler & IDEs Problem bei konvertiren eines char[] in einen integer


von Michael O. (michi26206)


Lesenswert?

Hallo zusammen,

ich übertragen via USART an einen Atmega16 Daten. Diese kommen dort in 
einem char array an. Nun möchte ich diesen char Array in einen Integer 
umwandeln.

ich habs mit folgendem versucht:
1
uint32_t recived_time_ticks;
2
char usart_string[7];
3
4
recived_time_ticks += ((usart_string[0] - '0') * 10000); //1
5
recived_time_ticks += ((usart_string[1] - '0') * 1000);
6
recived_time_ticks += ((usart_string[2] - '0') * 100);
7
recived_time_ticks += ((usart_string[3] - '0') * 10);
8
recived_time_ticks += (usart_string[4] - '0');
ich habe vom PC aus 72000 an den µC gesendet angekommen is aber: 64640. 
Dannach habe ich testweise die mit 1 kommentierte Zeile auskommentiert, 
jetzt kam 2000 an. Das würde passen. Irgendwie scheint ihm also die 
Multiplikation mit 10000 nicht zu gefallen.

Kann mir wer einen Tipp geben?

Gruß

von Lukas K. (carrotindustries)


Lesenswert?

Verscuhe mal
1
recived_time_ticks += (((uint32_t)usart_string[0] - (uint32_t)'0') * (uint32_t)10000); //1
Cast heißt das Zauberwort

von g457 (Gast)


Lesenswert?

> Irgendwie scheint ihm also die Multiplikation mit 10000 nicht zu gefallen.
> Kann mir wer einen Tipp geben?

Die Multiplikation in 32 Bit ausführen, sonst gibts bei 16 Bits einen 
Überlauf.

von Falk B. (falk)


Lesenswert?

Ist doch schon 32 Bit,

uint32_t recived_time_ticks;

kann aber auch sein, dass durch ein 5732te Sonderregel von C das bei der 
verkürzten Schreibweise nicht erkannt wird. Dann kann man das aber auch 
ohne Monster-Panik-Cast(ing) machen. Einfach ein L an die 10000 anfügen, 
damit wird das eine 32 Bit Konstante.

recived_time_ticks += ((usart_string[0] - '0') * 10000L); //1

MFG
Falk

von Michael O. (michi26206)


Lesenswert?

Danke an euch schon mal. Hab beides probiert.
Geht leider immer noch nicht. Werde mich jetzt aber mal schlafen legen 
und morgen weiter machen.

Gruß

von Rolf Magnus (Gast)


Lesenswert?

Falk Brunner schrieb:
> Ist doch schon 32 Bit,

Nein.

> uint32_t recived_time_ticks;

Das hat aber absolut nichts damit zu tun, mit welcher Bitbreite die 
Multiplikation durchgeführt wird.

> kann aber auch sein, dass durch ein 5732te Sonderregel von C das bei der
> verkürzten Schreibweise nicht erkannt wird.

Das hat nichts mit Sonderregeln oder einer verkürzten Schreibweise zu 
tun, sondern liegt schlicht daran, daß der Typ, mit dem eine Operation 
durchgeführt wird, immer nur von den Operanden abhängt und nie davon, 
was später mit dem Ergebnis gemacht wird.
Bei
1
((usart_string[0] - '0') * 10000)
sind beide Operanden der Multiplikation vom Typ int, also wird die 
Multiplikation in int durchgeführt.

von Falk B. (falk)


Lesenswert?

@  Rolf Magnus (Gast)

>Das hat nichts mit Sonderregeln oder einer verkürzten Schreibweise zu
>tun, sondern liegt schlicht daran, daß der Typ, mit dem eine Operation
>durchgeführt wird, immer nur von den Operanden abhängt und nie davon,
>was später mit dem Ergebnis gemacht wird.

Schon klar, aber

>((usart_string[0] - '0') * 10000)

>sind beide Operanden der Multiplikation vom Typ int, also wird die
>Multiplikation in int durchgeführt.

Falsch, dein "Zitat" ist ausserdem unvollständig.

1
recived_time_ticks += ((usart_string[0] - '0') * 10000); // Original
2
recived_time_ticks = recived_time_ticks + ((usart_string[0] - '0') * 10000); // Äquivalent

Somit steht jetzt eine 32 Bit Zahl auf der rechten Seite, womit ALLE 
anderen Zahlen erstmal in 32 Bit konvertiert werden, bevor gerechnet 
wird. Oder nicht?

MfG
Falk

von Rolf Magnus (Gast)


Lesenswert?

Falk Brunner schrieb:

> Schon klar, aber
>
>>((usart_string[0] - '0') * 10000)
>
>>sind beide Operanden der Multiplikation vom Typ int, also wird die
>>Multiplikation in int durchgeführt.
>
> Falsch, dein "Zitat" ist ausserdem unvollständig.

Nein, das ist nicht falsch, und das Zitat enthält alles, was für die 
Beantwortung der Frage, mit welchem Typ die Multiplikation durchgeführt 
wird, notwendig ist.

> recived_time_ticks += ((usart_string[0] - '0') * 10000); // Original
> recived_time_ticks = recived_time_ticks + ((usart_string[0] - '0') * 10000); // 
Äquivalent
>
> Somit steht jetzt eine 32 Bit Zahl auf der rechten Seite, womit ALLE
> anderen Zahlen erstmal in 32 Bit konvertiert werden, bevor gerechnet
> wird. Oder nicht?

Nein. Du mußt jede Operation einzeln betrachten. Deshalb: Es ist egal, 
was später mit dem Ergebnis passiert, es zählen ausschließlich die 
Operanden. Das heißt, es spielt keine Rolle, daß du das Ergebnis der 
Multiplikation später einer 32-Bit-Variablen zuweist.
Die Berechnung läuft in dieser Reihenfolge ab:

Durch die Klammerung kommt zuerst:
(ich führe mal für das Zwischenergebnis eine Variable 'tmp' ein)
1
tmp = usart_string[0] - '0'

Der linke Operand ist vom Typ char, der rechte vom Typ int, also wird 
zuerst der linke nach int konvertiert ("integer promotion"), dann wird 
die Subtraktion in int durchgeführt. tmp wäre also auch vom Typ int.

Jetz kommt
1
tmp2  = tmp * 10000;

tmp ist vom Typ int, 10000 auch, also wird die Multiplikation auch mit 
dem Typ int durchgeführt, und tmp2 ist ebenfalls vom Typ int. Jetzt 
kommt
1
received_time_ticks += tmp2;

received_time_ticks it vom typ uint32_t, tmp2 ist vom Typ int, also wird 
jetzt tmp2 nach uint32_t konvertiert und dann die Additon durchgeführt. 
Das heißt, daß nur diese eine Addition in 32 Bit abläuft, der Rest aber 
in 16 Bit.

von Falk B. (falk)


Lesenswert?

@  Rolf Magnus (Gast)

>Nein. Du mußt jede Operation einzeln betrachten. Deshalb: Es ist egal,
>was später mit dem Ergebnis passiert, es zählen ausschließlich die
>Operanden.

Ok, das ist dann wohl der Knackpunkt, der mir bisher nicht bekannt war. 
Ich dachte das wird auf die gesamte Rechnung auf einmal bezogen. Danke 
für die Aufklärung.

>Das heißt, daß nur diese eine Addition in 32 Bit abläuft, der Rest aber
>in 16 Bit.

Dann sollte aber mein Tip mit 10000L funktionieren. Oder der Fehler 
steckt woanders, wahrscheinlich in einem Pufferüberlauf und einem 
verschluckten ersten Zeichen. ;-)

@ OP

Um die Routine zu prüfen solltest du mal explizit im Programm den Puffer 
füllen und nicht per UART.

MfG
Falk

von Karl H. (kbuchegg)


Lesenswert?

Falk Brunner schrieb:

> Um die Routine zu prüfen solltest du mal explizit im Programm den Puffer
> füllen und nicht per UART.

@OT
1
uint32_t recived_time_ticks;
2
char usart_string[7];
3
4
recived_time_ticks += ((usart_string[0] - '0') * 10000); //1

zb wäre es schon von Vorteil, recived_time_ticks zunächt mit 0 zu 
initialisieren. Oder aber in der ersten Rechnung kein += sondern ein 
simples = zu machen.

Ansonsten:
Den String zum Sender zurücksenden oder sonst irgendwo ausgeben um 
nachzusehen, ob auch tatsächlich das angekommen ist, was du denkst das 
angekommen sein sollte. In der Kette

   Eingange  ->  Verarbeitung  ->  Ausgabe

kann der Fehler überall stecken. Auch im Schritt Eingabe. Ist die schon 
falsch, kannst du hinten nach suchen so viel du willst. Eine viel zu oft 
vergessene Regel sagt schliesslich "garbage in - garbage out". Wenn 
vorne schon Müll hineingesteckt wird, wird hinten auch immer Müll 
rauskommen.

von Michael O. (michi26206)


Lesenswert?

Der Buffer ist in Ordnung, ich hab ihn mir vor dem Verarbeiten immer 
ausgeben lassen.
Werde mich später melden, wenn ich mehr weis.

von Michael O. (michi26206)


Lesenswert?

Abend,

ich bin endlich wieder dazu gekommen:

habe folgendes ohne Erfolg versucht:
1
recived_time_ticks = 0;
2
recived_time_ticks = usart_string[0] - '0';
3
recived_time_ticks = (uint32_t)recived_time_ticks * (uint32_t)10000L; //1

leider ohne Erfolg. Hat jemand noch nen Tipp oder kennt wer ne 
unproblematischere Lösung um den char array in einen integer zu 
bekommen? Oder evtl. sogar ne einfachere Möglichkeit die 72000 über 
USART in den µC zu bekommen?

Gruß

von Falk B. (falk)


Lesenswert?

@  Michael O. (michi26206)

>habe folgendes ohne Erfolg versucht:

Das ist reine Panik, bringt aber rein gar nichts. Dein Problem liegt 
woanders. So reicht es.

1
recived_time_ticks = recived_time_ticks * usart_string[0] * 10000L; //1

Wie debuggst du denn? Vielleicht ist der Fehler in deiner Debugausgabe.

MfG
Falk

von Michael O. (michi26206)


Lesenswert?

Abend,

so ich bin jetzt alles nochmal durchgegagen.
Es war wie Ihr gesagt habt, die Rechnung war in Ordnung, aber die 
Ausgabe des Ergebnisses hat nicht gepasst, ich habe den Integer beim 
Ausgeben wieder in einen String umgewandelt, hierfür habe ich allerdings 
nicht die 32Bit (utoa) Methode verwendert sondern die 16 Bit (itoa).

Gruß & Danke @ all

von Karl H. (kbuchegg)


Lesenswert?

Michael O. schrieb:
> Abend,
>
> so ich bin jetzt alles nochmal durchgegagen.
> Es war wie Ihr gesagt habt, die Rechnung war in Ordnung, aber die
> Ausgabe des Ergebnisses hat nicht gepasst, ich habe den Integer beim
> Ausgeben wieder in einen String umgewandelt, hierfür habe ich allerdings
> nicht die 32Bit (utoa) Methode verwendert sondern die 16 Bit (itoa).

Immer noch falsch

   itoa      int              16 Bit mit Vorzeichen
   utoa      unsigned int     16 Bit ohne Vorzeichen
   ltoa      long             32 Bit mit Vorzeichen
   ultoa     unsigned long    32 Bit ohne Vorzeichen

von Michael O. (michi26206)


Lesenswert?

Da gebe ich dir natürlich sofort Recht ;-)
War ein Tippfehler meinerseits hier im Forum. Sry.

von Falk B. (falk)


Lesenswert?

Das zentrale Problem wird leicht übersehn. Dittrich Drahtlos ;-)

http://www.elektronik-bastelbude.de/Drahtlos/kap7a.htm

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.