Drukowanie znaków szesnastkowych w języku C

Próbuję odczytać wiersz znaków, a następnie wydrukować szesnastkowy odpowiednik znaków.

Na przykład, jeśli mam ciąg znaków "0xc0 0xc0 abc123", gdzie pierwsze 2 znaki to c0 w hex, a pozostałe znaki to abc123 W ASCII, to powinienem uzyskać

c0 c0 61 62 63 31 32 33

Jednak printf użycie %x daje mi

ffffffc0 ffffffc0 61 62 63 31 32 33

Jak uzyskać żądane wyjście bez "ffffff"? I dlaczego tylko c0 (i 80) mA ffffff, ale nie pozostałe znaki?

 72
Author: Prince John Wesley, 2011-11-09

7 answers

Widzisz ffffff ponieważ {[3] } jest podpisany w Twoim systemie. W C Funkcje vararg takie jak printf będą promować wszystkie liczby całkowite mniejsze od int do int. Ponieważ char jest liczbą całkowitą (w Twoim przypadku 8-bitowa signed integer), twoje znaki są promowane do int poprzez rozszerzenie sign.

Ponieważ c0 i 80 mają wiodący 1-bit (i są ujemne jako 8-bitowa liczba całkowita), są rozszerzane znakiem, podczas gdy inne w próbce nie.

char    int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061

Oto rozwiązanie:

char ch = 0xC0;
printf("%x", ch & 0xff);

To zamaskuje górne bity i zachowa tylko dolne 8 bitów, które chcesz.

 95
Author: Mysticial,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-09 04:52:45

W rzeczy samej, istnieje konwersja typu na int. Możesz również wymusić typ do znakowania za pomocą specyfikacji %hhx.

printf("%hhX", a);
 50
Author: brutal_lobster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-09 04:13:51

Możesz utworzyć znak unsigned:

unsigned char c = 0xc5;

Wydrukowanie go da C5, a nie ffffffc5.

Tylko znaki większe niż 127 są drukowane z ffffff, ponieważ są ujemne (znak jest podpisany).

Lub możesz rzucić char podczas drukowania:

char c = 0xc5; 
printf("%x", (unsigned char)c);
 24
Author: Hicham from CppDepend Team,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-28 08:43:35

Możesz użyć hh, aby powiedzieć printf że argument jest znakiem niepodpisanym. Użyj 0, aby uzyskać zero wypełnienia i 2, Aby ustawić szerokość na 2. x lub X dla małych / dużych znaków szesnastkowych.

uint8_t a = 0x0a;
printf("%02hhX", a); // Prints "0A"
printf("0x%02hhx", a); // Prints "0x0a"

Edit: jeśli czytelnicy są zaniepokojeni twierdzeniem 2501, że jest to jakoś nie "poprawny" format to proponuję przeczytać printf link Jeszcze raz. Konkretnie:

Mimo że %c oczekuje argumentu int, można bezpiecznie przekazać znak z powodu promocji liczby całkowitej, która ma miejsce, gdy wywołana jest zmienna funkcja.

Poprawne specyfikacje konwersji dla typów znaków o stałej szerokości (int8_t, etc) są zdefiniowane w nagłówku <cinttypes>(C++) lub <inttypes.h> (C) (chociaż PRIdMAX, PRIuMAX, etc jest synonimem %jd, % ju, etc) .

Jeśli chodzi o jego punkt o signed vs unsigned, w tym przypadku nie ma to znaczenia, ponieważ wartości muszą być zawsze pozytywne i łatwo zmieścić się w podpisanym int. Nie ma podpisanego formatu hexideximal i tak.

Edit 2 : (edycja" kiedy-przyznac-ze-sie-mylisz"):

Jeśli przeczytasz rzeczywisty standard C11 na stronie 311 (329 PDF) znajdziesz:

Hh: Określa, że następujące d, i, o, u, x, lub X specyfikator konwersji stosuje się do argumentu signed char lub unsigned char (argument będzie promowany zgodnie z promocjami całkowitymi, ale jego wartość będzie konwertowane do signed char lub unsigned char przed wydrukowaniem); lub że następujący specyfikator konwersji n stosuje się do wskaźnika do argumentu signed char.

 11
Author: Timmmm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-13 07:20:32

Prawdopodobnie przechowujesz wartość 0xc0 w zmiennej char, co prawdopodobnie jest typem podpisanym, a twoja wartość jest ujemna (najbardziej znaczący zestaw bitów). Następnie, podczas drukowania, jest on konwertowany na int i aby zachować równoważność semantyczną, kompilator wstawia dodatkowe bajty za pomocą 0xff, więc ujemny int będzie miał taką samą wartość liczbową jak Twój ujemny char. Aby to naprawić, po prostu wrzuć do unsigned char podczas drukowania:

printf("%x", (unsigned char)variable);
 10
Author: lvella,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-12 17:05:13

Prawdopodobnie drukujesz z podpisanej tablicy znaków. Albo wypisuje z tablicy znaków niepodpisanych, albo zamaskuje wartość za pomocą 0xff: np. ar[i] & 0xFF. Wartości c0 są rozszerzane, ponieważ ustawiony jest Bit wysoki (znak).

 2
Author: Richard Pennington,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-09 04:03:31

Spróbuj czegoś takiego:

int main()
{
    printf("%x %x %x %x %x %x %x %x\n",
        0xC0, 0xC0, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33);
}

Co daje:

$ ./foo 
c0 c0 61 62 63 31 32 33
 -1
Author: ObscureRobot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-15 17:43:07