Sida 1 av 2

sträng till int, i C?

Postat: 21 augusti 2006, 10:45:48
av Gimbal
Någon som vet en listig minnessnål metod att omvandla en sträng innehållande ett tvåsiffrigt hexadecimalt nummer till en int?

Tex "5B" till en int.

Det finns en färdig c-funktion för detta men den tar en hel del minne och det börjar bli lite trångt i Atmega88'an.

Har själv en del varianter löst skissade i huvudet, men någon kanske har en bättre ide.

Postat: 21 augusti 2006, 10:54:23
av Icecap
Jovars.....

Kod: Markera allt

word HexToInt(char * Data,byte Numbers)
  {
  word Result = 0;
  while(Numbers)
    {
    Result <<= 4;
    switch(*Data)
      {
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        Result += *Data - '0';
      break;
      case 'A':
      case 'B':
      case 'C':
      case 'D':
      case 'E':
      case 'F':
        Result += *Data - 'A' + 10;
      break;
      }
    Numbers--;
    Data++;
    }
  return(Result);
  }
alternativt

Kod: Markera allt

word HexToInt(char * Data,byte Numbers)
  {
  word Result = 0;
  while(Numbers)
    {
    Result <<= 4;
    if((*Data >= '0') && (*Data <= '9')) Result += *Data - '0';
    else if((*Data >= 'A') && (*Data <= 'F')) Result += *Data - 'A' + 10;
    // else ILLEGAL CHARACTER.....
    Numbers--;
    Data++;
    }
  return(Result);
  }

Postat: 21 augusti 2006, 11:23:24
av dennis
Eller så:

unsigned int hex2int(char *s)
{
unsigned char val;
val = *s>='a'?*s-('a'-10):*s-'0';
s++;
val <<= 4;
val += *s>='a'?*s-('a'-10):*s-'0';
return val;
}

int main(int argc, char *argv[])
{
char hexval[] = {"fe"};
printf("HexStr: %s Int: %.02x\n", hexval, hex2int(hexval));
}

Har iofs ingen koll på om det är illegala hextecken in....

Postat: 21 augusti 2006, 11:40:53
av Icecap
dennis: lite ineffktivt kanske.... samma funktion 2 gg. Kan också bara konvertera 2 tecken till en byte.

Men visst är den kompakt och att ändra den är ju snabbt.

Gimbal: i Dennis' rutin ska du tänka på att ändra alla 'a' till 'A' om du avser att köra versala och i min ska du ändra 'A' osv till deras gemener motsvarigheter om du vill köra gemener.

Ett alternativ som klarar allt legalt:

Kod: Markera allt

unsigned int Hex2Int(char * Data, char Numbers)
  {
  unsigned int Result;
  Result = 0;
  while(Numbers)
    {
    Result <<= 4;
    if((*Data >= '0') && (*Data <= '9') Result += *Data - '0';
    else if((*Data >= 'A') && (*Data <= 'F') Result += *Data - ('A' + 10);
    else if((*Data >= 'a') && (*Data <= 'f') Result += *Data - ('a' + 10);
// else ILLEGAL CHARACTER
    Numbers--;
    }
  return(Result);
  }

Postat: 21 augusti 2006, 12:51:01
av Gimbal
Tackar mjukast, Case-varianten var ungefär vad jag själv hade på lut. Men det blir till att prova vad som blir minst efter kompilering.

Siffran är aldrig större än "FF" kanske jag kunde ha nämnt, då det är en enkel XOR checksumma som ligger sist i de NMEA strängar som bl.a GPS'er häver ur sig.

Postat: 21 augusti 2006, 12:58:24
av sodjan
> Men det blir till att prova vad som blir minst efter kompilering...

Jämför även med den inbyggda rutinen !
Om den är ordentligt optimerad och skriven i ASM, så är det
inte alls säkert att en egen rutin i C blir mindre, hur bra den
än är skriven...

Postat: 21 augusti 2006, 13:25:10
av Gimbal
Givetvis, minst vinner. Men i detta fallet finns det hopp då den färdiga rutinen även klarade olika baser och inte bara hexadecimalt.

Postat: 21 augusti 2006, 14:16:25
av sodjan
OK, då kanske en egen C rutin blir mindre än just *den* rutinen,
men en egen asm rutin som gör precis det du vill skulle säkert vinna i alla fall...

Jag menar, 16 "case", som det var i ett exempel, hur ser det ut
efter kompilering ? Jag tror knappast att kompilatorn är så smart att
den "ser" att värderna till case ligger i nummerordning, utan det blir
sannolikt 16 st tester i asm...

Postat: 21 augusti 2006, 15:05:04
av Gimbal
Ja när det gäller mindre rutiner och enklare processorer så är handkodat svårslaget, och så är det ju iofs i detta fall.

Men det är fortfarande en liten bit kvar till minnestaket så innan det blir absolut stopp så är det C som gäller.

Postat: 21 augusti 2006, 19:37:11
av Gimbal
And here are the results from the Swedish jury.

De tre varianterna Icecap1, Icecap2 samt dennis1 var i slutändan väldigt lika. Men, vilket var huvudsaken, extremt mycket bättre än den mer generella standard C-funktionen.


Icecap1 tog acceptabla 1.7%
Icecap2 ännu bättre med 1.6%
och dennis1 rullar in på måttliga 1.8%

Den enda standardfunktionen jag hittade arbetade tyvärr med floats (strtol) och knaprade därför i sig ohyggliga 7.9% av minnet. Och nej, strtoi fanns inte.

Så vinsten i det här fallet (såvida ingen annan funktion finns) blir ganska fin.

8)

Postat: 21 augusti 2006, 19:52:46
av bearing
Hur lång tid de tar att köra kan vara intressant också.

Postat: 21 augusti 2006, 19:56:33
av Gimbal
Ja ibland så, fast inte denna gången. Det finns processorkraft så det räcker med råge.

Postat: 21 augusti 2006, 19:57:04
av sodjan
Och hur *ofta* de kommer att köras... :-)
Ju oftare, ju större anledning till optimering...

Förresten, hur många AVR instruktioner (ca) motsvarar "1.6 - 1.8 %"
(på den aktuella processorn, så klart...) ??

EDIT: antalet RAM/register som rutinen använder kan också vara intressant...

Postat: 21 augusti 2006, 20:14:04
av Gimbal
I det här fallet så används funktionen för att kolla checksumman på ett speciellt NMEA0183 meddelande som ramlar in max 1 gång per sekund. vilket i datorsammanhang är ungefär lika med aldrig.

Har tyvärr ingen aning om hur många instruktioner 1.6% motsvarar, men med 8KB minne så det blir det ca. 131 bytes.

Postat: 21 augusti 2006, 20:52:32
av dennis
Blev lite nyfiken så jag provade att kompilerade lite med gcc och mega48 som target.

icecap1 adderade 88 bytes.
icecap2 adderade 82 bytes.
dennis1 adderade 58 bytes.
strtol från avr libc adderade 802 bytes.

Man skall nog tänka på att när jag tog med strtol så följde nog en hel del annat från libc med också, så om den enda rutinen man behöver från libc är strtol så lönar det sig att göra en egen.