sträng till int, i C?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Gimbal
Inlägg: 8787
Blev medlem: 20 april 2005, 15:43:53

sträng till int, i C?

Inlägg 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.
Användarvisningsbild
Icecap
Inlägg: 26737
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg 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);
  }
Användarvisningsbild
dennis
Inlägg: 141
Blev medlem: 17 oktober 2005, 18:15:49
Ort: Olika

Inlägg 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....
Användarvisningsbild
Icecap
Inlägg: 26737
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg 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);
  }
Gimbal
Inlägg: 8787
Blev medlem: 20 april 2005, 15:43:53

Inlägg 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.
sodjan
EF Sponsor
Inlägg: 43267
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg 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...
Gimbal
Inlägg: 8787
Blev medlem: 20 april 2005, 15:43:53

Inlägg 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.
sodjan
EF Sponsor
Inlägg: 43267
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg 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...
Gimbal
Inlägg: 8787
Blev medlem: 20 april 2005, 15:43:53

Inlägg 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.
Gimbal
Inlägg: 8787
Blev medlem: 20 april 2005, 15:43:53

Inlägg 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)
bearing
Inlägg: 11682
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

Hur lång tid de tar att köra kan vara intressant också.
Gimbal
Inlägg: 8787
Blev medlem: 20 april 2005, 15:43:53

Inlägg av Gimbal »

Ja ibland så, fast inte denna gången. Det finns processorkraft så det räcker med råge.
sodjan
EF Sponsor
Inlägg: 43267
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg 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...
Gimbal
Inlägg: 8787
Blev medlem: 20 april 2005, 15:43:53

Inlägg 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.
Användarvisningsbild
dennis
Inlägg: 141
Blev medlem: 17 oktober 2005, 18:15:49
Ort: Olika

Inlägg 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.
Skriv svar