hexadecimale tekens afdrukken in C

Ik probeer een regel met tekens in te lezen en vervolgens het hexadecimale equivalent van de tekens af te drukken.

Als ik bijvoorbeeld een tekenreeks heb die "0xc0 0xc0 abc123"is, waarbij de eerste 2 tekens c0in hex zijn en de overige tekens abc123in ASCII, dan zou ik

. moeten krijgen

c0 c0 61 62 63 31 32 33

Echter, printfmet %xgeeft me

ffffffc0 ffffffc0 61 62 63 31 32 33

Hoe krijg ik de output die ik wil zonder de "ffffff"? En waarom heeft alleen c0 (en 80) de ffffff, maar niet de andere karakters?


Antwoord 1, autoriteit 100%

Je ziet de ffffffomdat charis ondertekend op je systeem. In C zullen vararg-functies zoals printfalle gehele getallen kleiner dan intpromoveren naar int. Aangezien chareen geheel getal is (8-bits geheel getal met teken in jouw geval), worden je tekens gepromoveerd tot intvia tekenextensie.

Aangezien c0en 80een leidende 1-bit hebben (en negatief zijn als een 8-bit integer), worden ze teken-uitgebreid terwijl de anderen in uw voorbeeld niet.

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

Hier is een oplossing:

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

Dit maskeert de bovenste bits en behoudt alleen de onderste 8 bits die je wilt.


Antwoord 2, autoriteit 45%

Er is inderdaad typeconversie naar int.
U kunt ook typen om char te forceren door de %hhx-specificatie te gebruiken.

printf("%hhX", a);

In de meeste gevallen wil je ook de minimumlengte instellen om het tweede teken met nullen te vullen:

printf("%02hhX", a);

ISO/IEC 9899:201x zegt:

7 De lengte-aanpassers en hun betekenis zijn:
hh Specificeert dat een volgende conversiespecificatie d, i, o, u, x of X van toepassing is op a
ondertekend char of unsigned char argument (het argument zal hebben
gepromoot volgens de integer-promoties, maar de waarde ervan zal zijn
geconverteerd naar ondertekende char of niet-ondertekende char voor het afdrukken); of dat
een volgende


Antwoord 3, autoriteit 21%

U kunt een niet-ondertekend teken maken:

unsigned char c = 0xc5;

Afdrukken geeft C5en niet ffffffc5.

Alleen de tekens groter dan 127 worden afgedrukt met de ffffffomdat ze negatief zijn (teken is ondertekend).

Of je kunt de charcasten tijdens het printen:

char c = 0xc5; 
printf("%x", (unsigned char)c);

Antwoord 4, autoriteit 10%

Je kunt hhgebruiken om printfdat het argument een teken zonder teken is. Gebruik 0om nul opvulling te krijgen en 2om de breedte in te stellen op 2. Xof Xvoor kleine letters/hoofdletters hexadecimale tekens.

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

Bewerken: als lezers zich zorgen maken over de bewering van 2501 dat dit op de een of andere manier niet de ‘juiste’ formaatspecificaties zijn, raad ik aan de printflinkopnieuw. Specifiek:

Hoewel %c een int-argument verwacht, is het veilig om een ​​char door te geven vanwege de integer-promotie die plaatsvindt wanneer een variadische functie wordt aangeroepen.

De juiste conversiespecificaties voor de tekentypen met vaste breedte (int8_t, enz.) zijn gedefinieerd in de kop <cinttypes>(C++) of <inttypes.h>(C) (hoewel PRIdMAX, PRIuMAX, enz. synoniem is met %jd, %ju, enz.).

Wat betreft zijn punt over ondertekend versus niet-ondertekend, in dit geval maakt het niet uit, omdat de waarden altijd positief moeten zijn en gemakkelijk in een ondertekend int moeten passen. Er is sowieso geen ondertekende hexadeximale formaatspecificatie.

Bewerk 2: (“when-to-admit-you’re-wrong” editie):

Als je de eigenlijke C11-standaardop pagina 311 (329 van de PDF) vindt u:

hh: Specificeert dat een volgende d, i, o, u, X, of Xconversiespecificatie is van toepassing op een signed charof unsigned charargument (het argument zal gepromoot zijn volgens de integer-promoties , maar de waarde ervan wordt geconverteerd naar signed charof unsigned charvoordat het wordt afgedrukt); of dat een volgende n-conversiespecificatie van toepassing is op een aanwijzer naar een signed char-argument.


Antwoord 5, autoriteit 9%

U slaat waarschijnlijk de waarde 0xc0 op in een charvariabele, wat waarschijnlijk een ondertekend type is, en uw waarde is negatief (meest significante bitset). Vervolgens wordt het tijdens het afdrukken geconverteerd naar inten om de semantische equivalentie te behouden, vult de compiler de extra bytes in met 0xff, zodat de negatieve inthetzelfde numerieke waarde van uw negatieve char. Om dit op te lossen, cast gewoon naar unsigned chartijdens het afdrukken:

printf("%x", (unsigned char)variable);

Antwoord 6

U drukt waarschijnlijk af vanuit een ondertekende char-array. Druk af vanuit een niet-ondertekende char-array of maskeer de waarde met 0xff: b.v. ar[i] & 0xFF. De c0-waarden krijgen een tekenverlenging omdat de hoge (teken)bit is ingesteld.


Antwoord 7

Probeer zoiets als dit:

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

Wat dit oplevert:

$ ./foo 
c0 c0 61 62 63 31 32 33

Other episodes