formatowanie printf () dla heksadecymalnego

191

To bardziej ciekawe pytanie niż ważne pytanie, ale dlaczego drukując szesnastkę jako 8 cyfr z zerami wiodącymi, nie %#08Xwyświetla tego samego wyniku co 0x%08X?

Kiedy próbuję użyć tego pierwszego, 08flaga formatowania jest usuwana i nie działa tylko z 8.

Znów byłem po prostu ciekawy.

wsmccusker
źródło
3
Czy masz na myśli 0x%.8X? Które będą prowadzić napełnić zerami. ( 0xto tylko preambuła, ale prawdopodobnie już o tym wiesz).
WhozCraig

Odpowiedzi:

283

#Część daje 0xw ciągu wyjściowym. Liczniki 0i xliczą się do twoich „8” znaków wymienionych w 08części. Musisz poprosić o 10 znaków, jeśli chcesz, aby były takie same.

int i = 7;

printf("%#010x\n", i);  // gives 0x00000007
printf("0x%08x\n", i);  // gives 0x00000007
printf("%#08x\n", i);   // gives 0x000007

Również zmiana wielkości liter xwpływa na wielkość znaków wyświetlanych znaków.

printf("%04x", 4779); // gives 12ab
printf("%04X", 4779); // gives 12AB
Mikrofon
źródło
Górna linia wyprowadza dla mnie 14F0x00000007. Druga i trzecia praca, jak napisano.
quantumpotato
@quantumpotato - To ... dziwne. Pierwszy i trzeci wiersz są identyczne, z wyjątkiem liczby zer, które powinny wygenerować. Jaki był twój kompilator / system / wiersz kodu, który to stworzył? Czy masz jakieś wiersze poprzedzające wydrukowany 14F?
Mike
19
Zauważ, że jeśli i = 0;używane wersje %#nie będą zawierać 0xprefiksu.
Jonathan Leffler,
ale co powiesz na hex: 0x43A66C31C68491C0 Próbowałem następujących rzeczy: __int64 int64 = 0x43A66C31C68491C0; printf_s ("% # 15X% d", int64, int64); Ale wyjście to 0XC68491C0, a nie 0x43A66C31C68491C0
123iamking
O heksie 0x43A66C31C68491C0 powyżej rozwiązałem go, rozwiązaniem jest 0x% I64X, a nie% #
15X
53

„0x” liczy się do liczby ośmiu znaków. Trzeba "%#010x".

Zauważ, że #nie nie dołączy 0x 0 - wynik będzie 0000000000- tak pewnie faktycznie należy po prostu użyć "0x%08x"tak.

Losowo 832
źródło
34

%#08XKonwersja musi poprzedzać wartość z 0X; jest to wymagane przez standard. W standardzie nie ma dowodów na to, że #powinien on zmienić zachowanie 08części specyfikacji, z wyjątkiem tego, że 0Xprefiks jest liczony jako część długości (więc możesz chcieć / potrzebować użyć %#010X. Jeśli, podobnie jak ja, podoba ci się twój hex prezentowany jako 0x1234CDEF, musisz użyć, 0x%08Xaby osiągnąć pożądany wynik. Możesz użyć %#.8Xi to również wstawić wiodące zera.

Wypróbuj odmiany następującego kodu:

#include <stdio.h>

int main(void)
{
    int j = 0;
    printf("0x%.8X = %#08X = %#.8X = %#010x\n", j, j, j, j);
    for (int i = 0; i < 8; i++)
    {
        j = (j << 4) | (i + 6);
        printf("0x%.8X = %#08X = %#.8X = %#010x\n", j, j, j, j);
    }
    return(0);
}

Na maszynie RHEL 5, a także w systemie Mac OS X (10.7.5), wynik był następujący:

0x00000000 = 00000000 = 00000000 = 0000000000
0x00000006 = 0X000006 = 0X00000006 = 0x00000006
0x00000067 = 0X000067 = 0X00000067 = 0x00000067
0x00000678 = 0X000678 = 0X00000678 = 0x00000678
0x00006789 = 0X006789 = 0X00006789 = 0x00006789
0x0006789A = 0X06789A = 0X0006789A = 0x0006789a
0x006789AB = 0X6789AB = 0X006789AB = 0x006789ab
0x06789ABC = 0X6789ABC = 0X06789ABC = 0x06789abc
0x6789ABCD = 0X6789ABCD = 0X6789ABCD = 0x6789abcd

Jestem trochę zaskoczony traktowaniem 0; Nie jestem pewien, dlaczego 0Xprefiks został pominięty, ale ponieważ robią to dwa oddzielne systemy, musi to być standard. Potwierdza to moje uprzedzenia wobec tej #opcji.


Traktowanie zera jest zgodne ze standardem.

ISO / IEC 9899: 2011 §7.21.6.1 funkcjafprintf

¶6 Znaki flag i ich znaczenie to:
...
#Wynik jest konwertowany na „alternatywną formę”. ... W przypadku x(lub X) konwersji niezerowy wynik ma 0x(lub 0X) przedrostek. ...

(Podkreślenie dodane.)


Zauważ, że użycie %#Xspowoduje użycie wielkich liter dla cyfr szesnastkowych i 0Xjako prefiksu; Użycie %#xspowoduje użycie małych liter dla cyfr szesnastkowych i 0xjako prefiksu. Jeśli wolisz 0xjako prefiksu i dużych liter, trzeba kodzie 0xoddzielnie: 0x%X. Oczywiście w razie potrzeby można dodać inne modyfikatory formatu.

Do drukowania adresów użyj <inttypes.h>nagłówka oraz makra uintptr_ttypu i PRIXPTRformatu:

#include <inttypes.h>
#include <stdio.h>

int main(void)
{
    void *address = &address;  // &address has type void ** but it converts to void *
    printf("Address 0x%.12" PRIXPTR "\n", (uintptr_t)address);
    return 0;
}

Przykładowe dane wyjściowe:

Address 0x7FFEE5B29428

Wybierz truciznę na długość - uważam, że dokładność 12 działa dobrze w przypadku adresów na komputerze Mac z systemem macOS. W połączeniu z .określeniem minimalnej precyzji (cyfr), niezawodnie formatuje adresy. Jeśli ustawisz precyzję na 16, dodatkowe 4 cyfry są zawsze z mojego doświadczenia na Macu równe 0, ale z pewnością należy rozważyć użycie 16 zamiast 12 w przenośnym 64-bitowym kodzie (ale użyłbyś 8 dla Kod 32-bitowy).

Jonathan Leffler
źródło