String zu Integer (Wer findet den Fehler?)

Gast #1150034
Lesenswert?

Hallo!

Ich bekomme über eine User-schnittstelle einen String. In erster Instanz 
verifiziere ich die Zeichen, sodass nur noch max. 5 Zahlen und evtl. ein 
Minuszeichen am Anfang enthalten sind.

z.B. "-12345" oder "12345"

Der Wertebereich soll den int-Datentyp entsprechen. D.h. Zahlen zw. 
-32768 und 32767 sollen gültig sein.

D.h. die Zahlen "-55555" oder "66666" sollen einen Fehler zurückgeben. 
(=Funktions-Return -1)

Die Funktion lautet folgendermassen:
1
char dezstr_2_int( unsigned char *string, int *value )
2
{
3
  unsigned char is_neg = 0, i;
4
  long int ret_value = 0;
5

6
  for( i = 0; i < 7; i++)
7
  {
8
    if(*(string + i) == 0x00) { break; }
9
  }
10

11
  for(; *string; string++ ) // string-to-integer - Umwandlung
12
  {
13
    if (*string == '-') { i--; is_neg = 1; continue; } // Vorzeichen auf negativ
14
    
15
    //Dezimalzahl umwandeln
16
    switch (i)
17
    {
18
      case 1: ret_value += (*string - 0x30); break;
19
      case 2: ret_value += ((*string - 0x30) * 10); break;
20
      case 3: ret_value += ((*string - 0x30) * 100); break;
21
      case 4: ret_value += ((*string - 0x30) * 1000); break;
22
      case 5: ret_value += ((*string - 0x30) * 10000); break;
23
    }
24
    i--;
25
  }
26

27
  if (is_neg) // in negative Zahl umwandeln
28
  {
29
    ret_value *= (-1);
30
  }
31

32
  //Bereich von Dezimalzahl prüfen und zurückgeben
33
  if (ret_value > -32769 && ret_value < 32768)
34
  {
35
    *value = (int)ret_value; // Zahl zurückgeben
36
    return 0;
37
  }
38

39
  return -1;
40
}

Solange der Wert zw. -39999 und 39999 schwankt, macht die Funktion, was 
sie soll. Liegt der Wert ausserhalb dieser Grenze kommt nur Müll raus 
(anstatt eines Fehlers '-1').

Irgendwie hab ich Tomaten auf den Augen, weil ich den Bug nicht finde.. 
:(

Bitte um Hilfe. - Danke!
#1150052
Lesenswert?

Geht bei mir wunderbar. Du musst natürlich auch auf den Fehler prüfen. 
In Value steht im Fehlerfall eine zufällige Zahl:
1
int main(int argc, char* argv[])
2
{
3
  int test;
4
  char test1[] = "40450";
5
  if(dezstr_2_int(test1,&test) == -1)
6
    printf("Fehler");  
7
  else
8
    printf("\n%d", test);
9

10
return 0;
11
}
#1150060
Lesenswert?

Timmo H. wrote:
> Geht bei mir wunderbar.

Hast du auf einem PC oder auf einem AVR getstet?

Kai hat das Problem schon richtig erkannt.
Auf einem AVR ist sizeof(int) == 2 und daher wird die
Multiplikation mit 10000 für viele Zahlen überlaufen.

Um das zu  umgehen, muss die Multiplikation als long gemacht werden.
1
    ((*string - 0x30) * 10000L);

Auf einem PC wirst du das Phänomen whrscheinlich so nicht sehen, da dort 
sizeof(int) heutzutage meistens 4 ist.
#1150083
Lesenswert?

Stefan Ernst wrote:
> Karl heinz Buchegger wrote:
>
1
>    if( *string == '-' )
2
>      is_neg = 1;
3
>
>
> ->
>
>
>
1
>    if( *string == '-' ) {
2
>      is_neg = 1;
3
>      string++;
4
>    }
5
>

und wieder mal die alte Weisheit:
Sei der Code auch noch so einfach - vor dem Posten testen!

Danke für den Catch.

und noch einer:
1
     ret_val = 10 * ret_val + ( *string++ + '0' )

--->
1
     ret_val = 10 * ret_val + ( *string++ - '0' )
Gast #1150266
Lesenswert?

@Ggg: Ja, das hab ich, ABER

karl heinz hat meinen 'Bug' (glaub ich jedenfalls, kann es momentan 
nicht testen) entdeckt -> Multiplikation ist mit einem Int-Wert, anstatt 
mit einem long int..! ;-)

Ich meld mich wieder, ob es das war..

Danke!
#1150273
Lesenswert?

Ggg wrote:
> Aber ret_value hat er doch mit long int definiert - D.h. 4 Byte
> lang..?!?
Ja und? Die Zuweisung wird als letztes ausgeführt (nach der Berechnung). 
Zum Zeitpunkt der Berechnung ist es dem Compiler piepegal, was links von 
dem "=" steht. Wenn nichts anderes angegeben ist, wird die Berechnung 
also in int durchgeführt, solange alle beteiligten Operanden in int 
darstellbar sind. Und in diesem Falle sind alle beteiligten Operanden in 
int darstellbar, weshalb die Berechnung auch in int durchgeführt 
wird.
#1150281
Lesenswert?

Ggg wrote:
> *hmm*
>
> Aber ret_value hat er doch mit long int definiert - D.h. 4 Byte
> lang..?!?

Und, wen kümmerts?

Das ist ein oft gemachter Irrglaube.
Der Datentyp der Ergebnissvariablen ist sowas von irrelevant! Wenn der 
Compiler entscheiden muss, wie eine bestimmte Operation durchzuführen 
ist, dann sieht er sich die beiden Operanden an! Einzig und alleine 
deren Datentyp entscheidet.

    3 / 5

3 ist ein int. 5 ist ein int. Also wird die Division als int-Division 
ausgeführt. Das du das Ergebnis

   double i = 3 / 5;

in einem double ablegst, ist für die Entscheidung wie die Division 
durchzuführen ist, nicht von Belang.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren