[Ogólnie] Konwersja ASCII -> HEX

W tym miejscu zadajemy pytania na temat języka C, dzielimy się swoją wiedzą, udzielamy wsparcia, rozwiązujemy problemy programistyczne.
Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

[Ogólnie] Konwersja ASCII -> HEX

Postautor: Antystatyczny » wtorek 05 sty 2016, 22:52

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?
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
j23
Expert
Expert
Posty: 506
Rejestracja: czwartek 08 paź 2015, 18:40

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

Postautor: j23 » środa 06 sty 2016, 05:29

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
Internet łączy ludzi, którzy dzielą się swoimi zainteresowaniami, pomysłami i potrzebami, bez względu na geograficzne (przeciwności).
BOB TAYLOR, PARC

Awatar użytkownika
PROTON
Expert
Expert
Posty: 527
Rejestracja: czwartek 08 paź 2015, 18:35
Lokalizacja: Warszawa

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

Postautor: PROTON » środa 06 sty 2016, 08:58

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/
Gott weiß ich will kein Engel sein.

Awatar użytkownika
mokrowski
User
User
Posty: 190
Rejestracja: czwartek 08 paź 2015, 20:50
Lokalizacja: Tam gdzie Centymetro

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

Postautor: mokrowski » środa 06 sty 2016, 10:24

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;
}
,,Myślenie nie jest łatwe, ale można się do niego przyzwyczaić" - Alan Alexander Milne: Kubuś Puchatek

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

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

Postautor: Antystatyczny » środa 06 sty 2016, 12:50

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?
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.


Wróć do „Pisanie programów w C”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 8 gości