Strona 1 z 1

[Ogólnie] Konwersja ASCII -> HEX

: wtorek 05 sty 2016, 22:52
autor: Antystatyczny
Witam

Mam łańcuch znaków, który zawiera reprezentację tekstową liczby w formacie heksadecymalnym. Niech to będzie np. "51".

Z dokumentacji modułu, który raczy mnie tymi danymi, wiem, że jest to postać hex, czyli dziesiętnie 81. Chciałbym ten łańcuch znaków przekształcić na postać liczbową zawartą w zmiennej typu uint8_t, ale... No właśnie, jedno ale. Funkcja atoi konwertuje ASCII do postaci liczbowej, ale w takiej postaci, jaką ją zastanie. Co to oznacza? Ano tyle, że jeśli wykonam taką operację:

Kod: Zaznacz cały

char tekst[] = "51";

uint8_t zmienna = atoi(tekst);

printf("%d", zmienna);


To w oknie konsoli zobaczę wyświetloną liczbę 51, co jest wciąż reprezentacją heksadecymalną. Prawidłowa wartość powinna być 81.

Znalazłem też funkcję strtol, ale tu trzeba jawnie rzutować i wygląda to mniej więcej tak:

Kod: Zaznacz cały

char *context;

zmienna = (uint8_t) strtol(tekst, &context, 16);


No i pytanie: Sposób z rzutowaniem oraz funkcją strtol jest słuszny, czy jest coś prostszego i bardziej eleganckiego, co zamieniłoby 51 w postaci hex ascii na dec int?

Re: [Ogólnie] Konwersja ASCII -> HEX

: środa 06 sty 2016, 05:29
autor: j23
Cześć Anty,

Chodzi chyba o specyfikator formatowania "%", czyli:
Zamiast tego:

Kod: Zaznacz cały

printf("%d", zmienna);


Użyj tego:

Kod: Zaznacz cały

printf("%x", zmienna);


Na stronie znalazłem też takie rozwiązanie:

Kod: Zaznacz cały

int x = 51;                           // dziesietnie 51
char ciag[32];                      // tu wyląduje ciąg wynikowy
sprintf ( ciag, "%x", x );


Pozdrawiam! j23 Jarek

Re: [Ogólnie] Konwersja ASCII -> HEX

: środa 06 sty 2016, 08:58
autor: PROTON
Dokładnie tak jak Jarek pokazał, tak się robi.
Dodał bym tylko jeszcze długość

sprintf ( ciag, "%.2x", x );

Wtedy hex wyjściowy wydłużany do 2 znaków a w puste miejsce będzie wstawiane 0.

Więcej na temat formatowania znajdziesz tutaj: http://www.cplusplus.com/reference/cstdio/printf/

Re: [Ogólnie] Konwersja ASCII -> HEX

: środa 06 sty 2016, 10:24
autor: mokrowski

Kod: Zaznacz cały

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

// Uwaga: Funkcja pozbawiona kontroli błędów.
uint16_t fast_atoi_hex(const char * str) {
   uint16_t result = 0;
   while(*str != 0) {
      result <<= 4;
      result += *str > '9' ? *str - '7' : *str - '0';
      str++;
   }
   return result;
}

int main(void) {
   char tekst[] = "AB51";
   uint16_t zmienna = fast_atoi_hex(tekst);
   printf("%d\n", zmienna);

   return EXIT_SUCCESS;
}

Re: [Ogólnie] Konwersja ASCII -> HEX

: środa 06 sty 2016, 12:50
autor: Antystatyczny
Dziękuję bardzo za odpowiedzi. Tak, odnośnie formatowania w funkcji printf już się dowiedziałem i wiem, że %d przedstawi mi liczbę w postaci dziesiętnej, a gdy użyję %x, funkcja printf zatroszczy się o konwersję liczby przekazanej do funkcji na postać heksadecymalną. Niestety wewnątrz "zmienna" nadal siedzi wartość przekonwertowana na postać dziesiętną z ASSCII HEX i porównanie received_checksum == calculated_checksum daje wynik false. W nocy trochę nad tym posiedziałem i stworzyłem taką funkcję:

Kod: Zaznacz cały

bool check_frame(char *frameptr)
{
   uint8_t received_checksum, calculated_checksum = 0;
   char *checksum_ptr;

   uint16_t data_counter = 0;

   //Najpierw znajdźmy sumę kontrolną w odebranym łańcuchu:
   strtok_s(frameptr, (const char*) "*", &checksum_ptr);

   //A następnie zamieńmy tekst na postać liczbową:
   received_checksum = (uint8_t)strtol(checksum_ptr, NULL, 16);

   //A teraz obliczamy własną sumę kontrolną. Jeśli będzie inna od odebranej, ramka jest uszkodzona.

   //Znak $ nie podlega xorowaniu (zgodnie z dokumentacją). Jeśli go tam nie było i usunąłem jakiś inny znak,
   //to znaczy, że ramka i tak przyszła niekompletna, bo każda ramka rozpoczyna się od znaku $.
   if (*frameptr == '$') frameptr++;

   while (*frameptr != 0)
   {
      calculated_checksum ^= *frameptr++;
      if (++data_counter > 255) return false;
   }
   return (received_checksum == calculated_checksum);
}


Spełnia swoje zadanie, bo testowałem ją na całych ramkach odebranych od gps.

@Mokrowski: Bardzo ciekawa fukcja i jak zwykle jej ciało nie jest takie oczywiste :) Oczywiście pochylę się nad nią... Widzę, że ona będzie tak długo konwertowała łańcuch, aż natrafi na NULL, czyli wymagałaby drobnej przeróbki w przypadku, gdybym zechciał z niej skorzystać gdzieś wewnątrz łańcucha.

Czy moja wersja funkcji sprawdzającej jest strawna, czy nie bardzo?